diff --git a/.gitignore b/.gitignore
index 32467d7dd1e7870d88336bb86dd53d29825095ee..75ae30bd2c43b1179aa62e408901ba973bfeb029 100755
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,8 @@ env/
 venv/
 *.pyc
 secure*
+*.aux
+*.log
+class.pdf
+class.tex
 .idea/
diff --git a/schoolapps/latex/.keep b/schoolapps/latex/.keep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/schoolapps/static/common/helper.js b/schoolapps/static/common/helper.js
new file mode 100644
index 0000000000000000000000000000000000000000..e0802213c9f99c29a0f9f6b564f7a57eba7c6e00
--- /dev/null
+++ b/schoolapps/static/common/helper.js
@@ -0,0 +1,65 @@
+function formatDate(date) {
+    return date.getDate() + "." + (date.getMonth() + 1) + "." + date.getFullYear();
+}
+
+
+function addZeros(i) {
+    if (i < 10) {
+        return "0" + i;
+    } else {
+        return "" + i;
+    }
+}
+
+function formatDateForDjango(date) {
+    return "" + date.getFullYear() + "/" + addZeros(date.getMonth() + 1) + "/" + addZeros(date.getDate()) + "/";
+
+}
+
+function getNow() {
+    return new Date();
+}
+
+function getNowFormatted() {
+    return formatDate(getNow());
+}
+
+
+$(document).ready(function () {
+    // Initialize sidenav [MAT]
+    $(".sidenav").sidenav();
+
+    // Initialize datepicker [MAT]
+    $('.datepicker').datepicker({
+        format: 'dd.mm.yyyy',
+        // Translate to German
+        i18n: {
+            months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
+            monthsShort: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],
+            weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
+            weekdaysShort: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
+            weekdaysAbbrev: ['S', 'M', 'D', 'M', 'D', 'F', 'S'],
+
+            // Buttons
+            today: 'Heute',
+            clear: 'Löschen',
+            done: 'OK',
+        },
+
+        // Set monday as first day of week
+        firstDay: 1,
+        autoClose: true
+    });
+
+    // Initialize timepicker [MAT]
+    $('.timepicker').timepicker({
+        twelveHour: false,
+        autoClose: true,
+        cancelText: 'Abbrechen',
+        clearText: 'Löschen',
+        doneText: 'OK'
+    });
+
+    //Initialize tooltip [MAT]
+    $('.tooltipped').tooltip();
+});
\ No newline at end of file
diff --git a/schoolapps/static/common/style.css b/schoolapps/static/common/style.css
index e4f6d35ee626bd8f541a233c3e5fb533a1545c5a..9e28771820a373b2d2291a7b1b52a2585eb2267c 100755
--- a/schoolapps/static/common/style.css
+++ b/schoolapps/static/common/style.css
@@ -144,6 +144,10 @@ span.badge.new::after {
     width: 100%;
 }
 
+table.substitutions td, table.substitutions th {
+    padding: 10px 5px;
+}
+
 /*.timetable-time {*/
 /*margin-right: 20px;*/
 /*}*/
@@ -173,4 +177,8 @@ span.badge.new::after {
 .btn-timetable-quicklaunch {
     margin: 1%;
     width: 30%;
+}
+
+table.striped > tbody > tr:nth-child(odd) {
+    background-color: rgba(208, 208, 208, 0.5);
 }
\ No newline at end of file
diff --git a/schoolapps/templates/partials/header.html b/schoolapps/templates/partials/header.html
index 5813c9d0e5189f2f3b7fa6bde8fc465b177de9bd..b020e0c1eaea1e81f8712ef4197d518d64d159ce 100755
--- a/schoolapps/templates/partials/header.html
+++ b/schoolapps/templates/partials/header.html
@@ -26,7 +26,8 @@
     <!---------------->
     <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
     <script src="{% static 'materialize/dist/js/materialize.min.js' %}"></script>
-    <script>
+    <script src="{% static 'common/helper.js' %}"></script>
+    <!--<script>
         $(document).ready(function () {
             // Initialize sidenav [MAT]
             $(".sidenav").sidenav();
@@ -65,7 +66,7 @@
             //Initialize tooltip [MAT]
             $('.tooltipped').tooltip();
         });
-    </script>
+    </script>-->
     <script>
         //set AUB-Form
         function set_time(lesson_field) {
@@ -98,7 +99,6 @@
     <!-- django-material -->
     {% include 'material/includes/material_js.html' %}
 
-
 </head>
 <body>
 <header>
diff --git a/schoolapps/timetable/pdf.py b/schoolapps/timetable/pdf.py
new file mode 100644
index 0000000000000000000000000000000000000000..811fc9f7977234c71f0f86a9cdad0030c91d610a
--- /dev/null
+++ b/schoolapps/timetable/pdf.py
@@ -0,0 +1,169 @@
+import os
+import subprocess
+
+from django.utils import timezone
+from django.utils import formats
+
+# LaTeX constants
+
+TEX_HEADER = """\\documentclass[11pt]{article}
+\\usepackage[ngerman]{babel}
+\\usepackage[utf8]{inputenc}
+\\usepackage[a4paper,left=1cm,right=1cm,top=2cm,bottom=2cm,bindingoffset=0mm]{geometry}
+
+\\usepackage{fancyhdr}
+\\usepackage{graphicx}
+
+\\usepackage{longtable}
+\\usepackage{multirow}
+\\usepackage{color, colortbl}
+
+\\usepackage{geometry}
+
+\\usepackage{ulem, xpatch}
+\\xpatchcmd{\\sout}
+  {\\bgroup}
+  {\\bgroup\def\\ULthickness{1.5pt}}
+  {}{}
+  
+\\usepackage[framemethod=tikz]{mdframed}
+\\newmdenv[
+  roundcorner=5pt,
+  backgroundcolor=green,
+  linecolor=green,
+  skipabove=0pt,
+  skipbelow=0pt,
+  leftmargin=0pt,
+  rightmargin=0pt
+]{badges}
+
+\\usepackage{tcolorbox}
+\\newtcbox{\\badge}{nobeforeafter,colframe=green,colback=green,boxrule=0.5pt,arc=4pt,
+  boxsep=0pt,left=5pt,right=5pt,top=5pt,bottom=5pt,tcbox raise base,
+  grow to left by=0pt,
+  grow to right by=-3pt,
+  enlarge top by=3pt,
+  enlarge bottom by=3pt,coltext=white}
+
+  
+\\usepackage{helvet} %Helvetica als Standardschriftart
+\\renewcommand{\\familydefault}{\\sfdefault} %Helvetica als Standardschriftart
+
+\\definecolor{grey}{rgb}{0.95,0.95,0.95}
+\\definecolor{darkgrey}{rgb}{0.6,0.6,0.6}
+\\definecolor{white}{rgb}{1,1,1}
+\\definecolor{green}{RGB}{76,175,80}
+
+\\pagestyle{fancy}
+%\\renewcommand{\\sectionmark}[1]{#1}
+%\\lhead{\\rightmark}
+\\lhead{\\includegraphics[width=5cm]{static/common/logo.png}}
+\\lfoot{Katharineum zu Lübeck}
+\\cfoot{\\thepage}
+\\rfoot{\\small Umsetzung: © 2018 by Computer-AG}
+
+\\begin{document}"""
+
+TEX_FOOTER = '\end{document}'
+
+TEX_TABLE_HEADER_CLASS = """
+\def\\arraystretch{1.5}
+\\begin{longtable}{|p{20mm}|p{10mm}|p{32mm}|p{25mm}|p{30mm}|p{35mm}|}
+\\hline\n
+\\rowcolor{darkgrey}
+\\color{white}\\textbf{Klasse} & 
+\\color{white}\\textbf{Std.} & 
+\\color{white}\\textbf{Lehrer} & 
+\\color{white}\\textbf{Fach} & 
+\\color{white}\\textbf{Raum} & 
+\\color{white}\\textbf{Hinweis}\\\\\\hline
+"""
+
+TEX_HEADER_CLASS = """
+\\rhead{\\textbf{Vertretungen %s}\\\\Stand: %s\\\\ }
+\\Large
+\\subsubsection*{}
+\\section*{\\Huge Vertretungen %s}
+\n"""
+
+
+def generate_pdf(tex, filename):
+    """Generate a PDF by LaTeX code"""
+
+    # Read LaTeX file
+    tex_file = open(os.path.join("latex", filename + ".tex"), "w")
+    tex_file.write(tex)
+    tex_file.close()
+
+    # Execute pdflatex to generate the PDF
+    bash_command = "pdflatex -output-directory latex {}.tex".format(filename)
+    process = subprocess.Popen(bash_command.split(), stdout=subprocess.PIPE)
+    output = process.communicate()[0]
+
+
+def tex_replacer(s):
+    """Replace HTML tags by LaTeX tags"""
+
+    # Strong text
+    s = s.replace("<strong>", "\\textbf{")
+    s = s.replace("</strong>", "}")
+
+    # Struck out text
+    s = s.replace("<s>", "\\sout{")
+    s = s.replace("</s>", "}")
+
+    # Arrow
+    s = s.replace("→", "$\\rightarrow$")
+
+    return s
+
+
+def generate_class_tex(subs, date):
+    """Generate LaTeX for a PDF by a substitution table"""
+    tex_body = ""
+
+    # Format dates
+    status_date = formats.date_format(date, format="j. F Y, \\K\\W W ")
+    current_date = formats.date_format(timezone.datetime.now(), format="j. F Y H:i")
+    head_date = formats.date_format(date, format="l, j. F Y")
+
+    # Generate header with dates
+    tex_body += TEX_HEADER_CLASS % (status_date, current_date, head_date)
+
+    # Begin table
+    tex_body += TEX_TABLE_HEADER_CLASS
+
+    color_background = True
+    for sub in subs:
+        # Color every second row in grey
+        if color_background:
+            tex_body += '\\rowcolor{grey}'
+
+        # Get color tag for row
+        color = "\color{%s}" % sub.color
+
+        # Print classes
+        tex_body += color
+        tex_body += '\\textbf{' + sub.classes + '} & '
+
+        # Print lesson number, teacher, subject and room
+        for i in [sub.lesson, sub.teacher, sub.subject, sub.room]:
+            tex_body += color
+            tex_body += tex_replacer(i) + ' & '
+
+        # Print badge (Cancellation)
+        if sub.badge is not None:
+            tex_body += """\\large\\badge{%s}""" % sub.badge
+
+        # Print notice and new line
+        tex_body += color
+        tex_body += "\\Large\\textit{%s}\\\\\\hline\n" % (sub.text or "")
+
+        # Change background
+        color_background = not color_background
+    # End table
+    tex_body += '\\end{longtable}'
+
+    # Connect header, body and footer
+    tex_content = TEX_HEADER + tex_body + TEX_FOOTER
+    return tex_content
diff --git a/schoolapps/timetable/templates/timetable/substitution.html b/schoolapps/timetable/templates/timetable/substitution.html
index 02e8f2719198462fb91addfe7f92451ce4709be5..6099c0337841892091a00954865f209441100575 100755
--- a/schoolapps/timetable/templates/timetable/substitution.html
+++ b/schoolapps/timetable/templates/timetable/substitution.html
@@ -1,12 +1,139 @@
 {% include 'partials/header.html' %}
 
+<script type="text/javascript">
+    function updateDatepicker() {
+        $("#date").val(formatDate(activeDate));
+    }
+
+    function update() {
+        console.log("Render new.");
+
+        updateDatepicker();
+    }
+
+    function loadNew() {
+        window.location.href = "/timetable/substitutions/" + formatDateForDjango(activeDate);
+    }
+
+    function onDateBeforeClick() {
+        activeDate.setDate(activeDate.getDate() - 1);
+        update();
+        loadNew();
+    }
+
+    function onDateNextClick() {
+        activeDate.setDate(activeDate.getDate() + 1);
+        update();
+        loadNew();
+    }
+
+    function onDateChanged() {
+        var str = $("#date").val();
+        var split = str.split(".")
+        activeDate = new Date(split[2], split[1] - 1, split[0]);
+        update();
+        loadNew();
+    }
+
+    var activeDate = new Date({{ date_js }});
+
+    $(document).ready(function () {
+        $("#date-before").click(onDateBeforeClick);
+        $("#date-next").click(onDateNextClick);
+        $("#date").change(onDateChanged);
+
+        // Print the site
+        $("#print").click(function () {
+            window.print();
+        });
+
+        update();
+    })
+</script>
+
 <main>
     <h3>Vertretungen</h3>
 
-    <p class="flow-text">
-        Leider ist der Vertretungsplan noch nicht in Betrieb. Nutzen Sie solange die <a
-            href="https://info.katharineum.de/aktuell.pdf">alte Version</a>. Vielen Dank!
-    </p>
+    <div class="row">
+        <div class="col s12 m6 l4 xl3">
+            <div class="col s2">
+                <a class="waves-effect waves-teal btn-flat btn-flat-medium right" id="date-before">
+                    <i class="material-icons center">navigate_before</i>
+                </a>
+
+            </div>
+            <div class="col s8">
+                <input type="text" class="datepicker center-align" id="date">
+            </div>
+            <div class="col s2">
+                <a class="waves-effect waves-teal btn-flat btn-flat-medium left" id="date-next">
+                    <i class="material-icons center">navigate_next</i>
+                </a>
+            </div>
+        </div>
+        <div class="col l4 xl6">
+        </div>
+        <div class="col s12 m6 l4 xl3 right align-right">
+            <a class="waves-effect waves-teal btn-flat btn-flat-medium right" id="print">
+                <i class="material-icons center">print</i>
+            </a>
+        </div>
+    </div>
+
+    <h5>{{ date|date:"l, j. F Y" }}</h5>
+
+    <table class="substitutions striped">
+        <thead>
+        <tr>
+            <th><i class="material-icons">access_time</i></th>
+            <th>Klassen</th>
+            <th>Lehrer</th>
+            <th>Fach</th>
+            <th>Raum</th>
+            <th>Hinweis</th>
+            <th></th>
+        </tr>
+        </thead>
+        <tbody>
+        {% for sub in sub_table %}
+            <tr class="{{ sub.css_class }}">
+                <td>
+                    <strong>
+                        {{ sub.lesson }}
+                    </strong>
+                </td>
+                <td>
+                    {{ sub.classes }}
+                </td>
+                <td>
+                    <span class="tooltipped" data-position="bottom"
+                          data-tooltip="{{ sub.teacher_full|safe }}">{{ sub.teacher|safe }}</span>
+                </td>
+                <td>
+                    {{ sub.subject|safe }}
+                </td>
+                <td>
+                    <span class="tooltipped" data-position="bottom"
+                          data-tooltip="{{ sub.room_full|safe }}">{{ sub.room|safe }}</span>
+                </td>
+                <td>
+                    {% if sub.badge %}
+                        <span class="badge new green hide-on-med-and-up">{{ sub.badge }}</span>
+                    {% endif %}
+                    <em>{{ sub.text|default:"" }}</em>
+                </td>
+                <td class="hide-on-small-and-down">
+
+                    {% if sub.badge %}
+                        <span class="badge new green">{{ sub.badge }}</span>
+                    {% endif %}
+
+                </td>
+            </tr>
+        {% endfor %}
+        </tbody>
+    </table>
+
 </main>
 
 {% include 'partials/footer.html' %}
diff --git a/schoolapps/timetable/urls.py b/schoolapps/timetable/urls.py
index 3b79722e07404fe38765e97a9a13233e2acd46b6..9e7c7dcf253b593405fa9281af470d0bb95c68be 100755
--- a/schoolapps/timetable/urls.py
+++ b/schoolapps/timetable/urls.py
@@ -3,7 +3,9 @@ from . import views
 
 urlpatterns = [
     path('', views.all, name='timetable_admin_all'),
-    path('quick', views.quicklaunch, name='timetable_quicklaunch'),
-    path('<str:plan_type>/<int:plan_id>', views.plan, name='timetable_plan'),
-    path('substitutions', views.substitutions, name='timetable_substitutions'),
+    path('quick/', views.quicklaunch, name='timetable_quicklaunch'),
+    path('<str:plan_type>/<int:plan_id>/', views.plan, name='timetable_plan'),
+    path('substitutions/', views.substitutions, name='timetable_substitutions'),
+    path('substitutions/<int:year>/<int:month>/<int:day>/', views.substitutions, name='timetable_substitutions_date'),
+    path('class.pdf', views.sub_pdf, name="timetable_substitutions_pdf")
 ]
diff --git a/schoolapps/timetable/views.py b/schoolapps/timetable/views.py
index 7d7bed5e419154af8c078b0b896e93f51487c56e..8a9a586cf3a61830ec6d5ec8b3002d7a70628883 100755
--- a/schoolapps/timetable/views.py
+++ b/schoolapps/timetable/views.py
@@ -1,12 +1,16 @@
 import datetime
+import os
 
 from django.contrib.auth.decorators import login_required, permission_required
-from django.http import Http404
+from django.http import Http404, FileResponse
 from django.shortcuts import render
 from django.utils import timezone
 
+from timetable.pdf import generate_class_tex, generate_pdf
 from schoolapps.settings import LESSONS
+
 from untisconnect.parse import *
+from untisconnect.sub import get_substitutions_by_date, date_to_untis_date, untis_date_to_date, generate_sub_table
 
 try:
     from schoolapps.untisconnect.api import *
@@ -70,7 +74,58 @@ def plan(request, plan_type, plan_id):
     return render(request, 'timetable/plan.html', context)
 
 
+def get_next_weekday(date):
+    """Get the next weekday by a datetime object"""
+
+    if date.isoweekday() in {6, 7}:
+        if date.isoweekday() == 6:
+            plus = 2
+        else:
+            plus = 1
+        date += datetime.timedelta(days=plus)
+    return date
+
+
+def sub_pdf(request):
+    """Show substitutions as PDF for the next weekday (specially for monitors)"""
+
+    # Get the next weekday
+    today = timezone.datetime.now()
+    first_day = get_next_weekday(today)
+
+    # Get subs and generate table
+    subs = get_substitutions_by_date(first_day)
+    sub_table = generate_sub_table(subs)
+
+    # Generate LaTeX
+    tex = generate_class_tex(sub_table, first_day)
+
+    # Generate PDF
+    generate_pdf(tex, "class")
+
+    # Read and response PDF
+    file = open(os.path.join("latex", "class.pdf"), "rb")
+    return FileResponse(file, content_type="application/pdf")
+
+
 @login_required
 @permission_required("timetable.show_plan")
-def substitutions(request):
-    return render(request, 'timetable/substitution.html')
+def substitutions(request, year=None, day=None, month=None):
+    """Show substitutions in a classic view"""
+
+    date = timezone.datetime.now()
+    if year is not None and day is not None and month is not None:
+        date = timezone.datetime(year=year, month=month, day=day)
+
+    # Get subs and generate table
+    subs = get_substitutions_by_date(date)
+    sub_table = generate_sub_table(subs)
+
+    context = {
+        "subs": subs,
+        "sub_table": sub_table,
+        "date": date,
+        "date_js": int(date.timestamp()) * 1000
+    }
+
+    return render(request, 'timetable/substitution.html', context)
diff --git a/schoolapps/untisconnect/api.py b/schoolapps/untisconnect/api.py
index b1e8c01bbd1575a9dd5498509ff1f5edbf1a3c06..598b00ffcad34eba66707d1acd1c193d114ea13c 100755
--- a/schoolapps/untisconnect/api.py
+++ b/schoolapps/untisconnect/api.py
@@ -25,8 +25,7 @@ def run_default_filter(obj, filter_term=True):
         return obj.filter(school_id=SCHOOL_ID, schoolyear_id=SCHOOLYEAR_ID, version_id=VERSION_ID)
 
 
-def row_by_row(db_ref, obj, filter_term=True):
-    db_rows = run_all(db_ref.objects, filter_term=filter_term)
+def row_by_row_helper(db_rows, obj):
     out_rows = []
     for db_row in db_rows:
         o = obj()
@@ -35,6 +34,11 @@ def row_by_row(db_ref, obj, filter_term=True):
     return out_rows
 
 
+def row_by_row(db_ref, obj, filter_term=True):
+    db_rows = run_all(db_ref.objects, filter_term=filter_term)
+    return row_by_row_helper(db_rows, obj)
+
+
 def one_by_id(db_ref, obj):
     # print(db_ref)
     if db_ref != None:
@@ -154,6 +158,38 @@ def get_room_by_id(id):
     return one_by_id(room, Room)
 
 
+########
+# CORRIDOR #
+########
+class Corridor(object):
+    def __init__(self):
+        self.filled = False
+        self.id = None
+        self.name = None
+
+    def __str__(self):
+        if self.filled:
+            return self.name or "Unbekannt"
+        else:
+            return "Unbekannt"
+
+    def create(self, db_obj):
+        self.filled = True
+        self.id = db_obj.corridor_id
+        self.name = db_obj.name
+
+
+def get_all_corridors():
+    corridors = row_by_row(models.Corridor, Corridor, filter_term=False)
+    return corridors
+
+
+def get_corridor_by_id(id):
+    print(id)
+    corridor = run_one(models.Corridor.objects, filter_term=False).get(corridor_id=id)
+    return one_by_id(corridor, Corridor)
+
+
 ###########
 # SUBJECT #
 ###########
diff --git a/schoolapps/untisconnect/api_helper.py b/schoolapps/untisconnect/api_helper.py
index be7b58107c2cb080025aa6f34427b183581684a0..5ec087772424e2f28dd28e45116cb06806b33865 100644
--- a/schoolapps/untisconnect/api_helper.py
+++ b/schoolapps/untisconnect/api_helper.py
@@ -21,7 +21,7 @@ def run_using(obj):
 
 def get_term_by_id(term_id):
     data = run_using(models.Terms.objects).get(term_id=term_id)
-    print(data.schoolyear_id)
+    # print(data.schoolyear_id)
     return data
 
 
@@ -47,5 +47,30 @@ def get_terms():
         term = Term()
         term.create(item)
         terms.append(term)
-        print(term.name)
+        # print(term.name)
     return terms
+
+
+################
+# HELP METHODS #
+################
+def clean_array(a, conv=None):
+    b = []
+    for el in a:
+        if el != '' and el != "0":
+            if conv is not None:
+                el = conv(el)
+            b.append(el)
+    return b
+
+
+def untis_split_first(s, conv=None):
+    return clean_array(s.split(","), conv=conv)
+
+
+def untis_split_second(s, conv=None):
+    return clean_array(s.split("~"), conv=conv)
+
+
+def untis_split_third(s, conv=None):
+    return clean_array(s.split(";"), conv=conv)
diff --git a/schoolapps/untisconnect/parse.py b/schoolapps/untisconnect/parse.py
index b09a56d9d85ce19df3eb0dd14893c9a010431ce9..73731d8c18c7570e8b78587eb08d91921d05ffe5 100755
--- a/schoolapps/untisconnect/parse.py
+++ b/schoolapps/untisconnect/parse.py
@@ -21,9 +21,75 @@ class Lesson(object):
         el.create(day, hour, rooms)
         self.times.append(el)
 
-    def create(self, db_obj):
+    def create(self, raw_lesson, drive):
         self.filled = True
 
+        # Split data (,)
+        lesson_id = raw_lesson.lesson_id
+        raw_lesson_data = raw_lesson.lessonelement1.split(",")
+        raw_time_data = raw_lesson.lesson_tt.split(",")
+
+        rtd2 = []
+        for el in raw_time_data:
+            rtd2.append(el.split("~"))
+
+        # print(rtd2)
+
+        for el in rtd2:
+            day = int(el[1])
+            hour = int(el[2])
+            room_ids = untis_split_third(el[3], conv=int)
+
+            rooms = []
+            for room_id in room_ids:
+                r = drive["rooms"][room_id]
+                rooms.append(r)
+
+            self.add_time(day, hour, rooms)
+
+        # print(raw_lesson_data)
+        # print(raw_time_data)
+
+        # Split data more (~)
+        rld2 = []
+        for el in raw_lesson_data:
+            rld2.append(el.split("~"))
+
+        # print(rld2)
+
+        for el in rld2:
+            teacher_id = int(el[0])
+            subject_id = int(el[2])
+            room_ids = untis_split_third(el[4], int)
+            class_ids = untis_split_third(el[17], conv=int)
+            # print("TEACHER – ", teacher_id, "; SUBJECT – ", subject_id, "; ROOMS – ", room_ids, "; CLASSES – ",
+            #       class_ids)
+
+            if teacher_id != 0:
+                teacher = drive["teachers"][teacher_id]
+            else:
+                teacher = None
+
+            if subject_id != 0:
+                subject = drive["subjects"][subject_id]
+            else:
+                subject = None
+
+            rooms = []
+            for room_id in room_ids:
+                r = drive["rooms"][room_id]
+                rooms.append(r)
+
+            classes = []
+            for class_id in class_ids:
+                c = drive["classes"][class_id]
+                classes.append(c)
+
+            # print("TEACHER – ", teacher, "; SUBJECT – ", subject, "; ROOMS – ", rooms,
+            #       "; CLASSES – ", classes)
+
+            self.add_element(teacher, subject, rooms, classes)
+
 
 class LessonElement(object):
     def __init__(self):
@@ -52,43 +118,39 @@ class LessonTime(object):
 
 
 from .api import *
+from .api_helper import untis_split_third
 
 
-def clean_array(a, conv=None):
-    b = []
-    for el in a:
-        if el != '' and el != "0":
-            if conv is not None:
-                el = conv(el)
-            b.append(el)
-    return b
-
-
-def untis_split(s, conv=None):
-    return clean_array(s.split(";"), conv=conv)
-
-
-def parse():
+def build_drive():
     odrive = {
         "teachers": get_all_teachers(),
         "rooms": get_all_rooms(),
         "classes": get_all_classes(),
-        "subjects": get_all_subjects()
+        "subjects": get_all_subjects(),
+        "corridors": get_all_corridors(),
     }
 
     drive = {
-        "teachers": {},
-        "rooms": {},
-        "classes": {},
-        "subjects": {}
+        # "teachers": {},
+        # "rooms": {},
+        # "classes": {},
+        # "subjects": {}
     }
     for key, value in odrive.items():
+        drive[key] = {}
         for el in value:
             id = el.id
             drive[key][id] = el
 
     print(drive)
+    return drive
+
 
+drive = build_drive()
+
+
+def parse():
+    global drive
     lessons = []
     raw_lessons = get_raw_lessons()
 
@@ -101,74 +163,7 @@ def parse():
         if raw_lesson.lesson_tt and raw_lesson.lessonelement1:
             # Create object
             lesson_obj = Lesson()
-
-            # Split data (,)
-            lesson_id = raw_lesson.lesson_id
-            raw_lesson_data = raw_lesson.lessonelement1.split(",")
-            raw_time_data = raw_lesson.lesson_tt.split(",")
-
-            rtd2 = []
-            for el in raw_time_data:
-                rtd2.append(el.split("~"))
-
-            # print(rtd2)
-
-            for el in rtd2:
-                day = int(el[1])
-                hour = int(el[2])
-                room_ids = untis_split(el[3], conv=int)
-
-                rooms = []
-                for room_id in room_ids:
-                    r = drive["rooms"][room_id]
-                    rooms.append(r)
-
-                lesson_obj.add_time(day, hour, rooms)
-
-            # print(raw_lesson_data)
-            # print(raw_time_data)
-
-            # Split data more (~)
-            rld2 = []
-            for el in raw_lesson_data:
-                rld2.append(el.split("~"))
-
-            # print(rld2)
-
-            for i, el in enumerate(rld2):
-                teacher_id = int(el[0])
-                subject_id = int(el[2])
-                # room_ids = untis_split(el[4], int)
-                class_ids = untis_split(el[17], conv=int)
-                # print("TEACHER – ", teacher_id, "; SUBJECT – ", subject_id, "; ROOMS – ", room_ids, "; CLASSES – ",
-                #       class_ids)
-
-                if teacher_id != 0:
-                    teacher = drive["teachers"][teacher_id]
-                else:
-                    teacher = None
-
-                if subject_id != 0:
-                    subject = drive["subjects"][subject_id]
-                else:
-                    subject = None
-
-                rooms = []
-                # for room_id in room_ids:
-                # r = drive["rooms"][room_ids[i]]
-                # rooms.append(r)
-
-                classes = []
-                for class_id in class_ids:
-                    c = drive["classes"][class_id]
-                    classes.append(c)
-
-                # print("TEACHER – ", teacher, "; SUBJECT – ", subject, "; ROOMS – ", rooms,
-                #       "; CLASSES – ", classes)
-
-                lesson_obj.add_element(teacher, subject, rooms, classes)
-
-                # print("DAY – ", day, "; HOUR – ", hour, "; ROOMS – ", room_ids)
+            lesson_obj.create(raw_lesson, drive)
 
             lessons.append(lesson_obj)
 
@@ -208,6 +203,26 @@ class LessonElementContainer(object):
         self.room = room
 
 
+def get_lesson_by_id(id):
+    global drive
+    lesson = Lesson()
+    raw_lesson = run_one(models.Lesson.objects, filter_term=True).get(lesson_id=id)
+    lesson.create(raw_lesson, drive)
+    return lesson
+
+
+def get_lesson_element_by_id_and_teacher(lesson_id, teacher):
+    print(lesson_id)
+    try:
+        lesson = get_lesson_by_id(lesson_id)
+    except Exception:
+        return None
+    for element in lesson.elements:
+        print(element.teacher.shortcode)
+        if element.teacher.id == teacher.id:
+            return element
+    return None
+
 def parse_lesson_times():
     times = []
     for i, t in enumerate(LESSONS):
diff --git a/schoolapps/untisconnect/sub.py b/schoolapps/untisconnect/sub.py
new file mode 100644
index 0000000000000000000000000000000000000000..e4e21239e07428066affaad0591ec99777fc3799
--- /dev/null
+++ b/schoolapps/untisconnect/sub.py
@@ -0,0 +1,259 @@
+from django.utils import timezone
+
+from untisconnect import models
+from untisconnect.api import run_default_filter, row_by_row_helper, get_teacher_by_id, get_subject_by_id, \
+    get_room_by_id, get_class_by_id, get_corridor_by_id
+from untisconnect.api_helper import run_using, untis_split_first
+from untisconnect.parse import get_lesson_by_id, get_lesson_element_by_id_and_teacher, build_drive
+
+DATE_FORMAT = "%Y%m%d"
+
+
+def untis_date_to_date(untis):
+    return timezone.datetime.strptime(str(untis), DATE_FORMAT)
+
+
+def date_to_untis_date(date):
+    return date.strftime(DATE_FORMAT)
+
+
+TYPE_SUBSTITUTION = 0
+TYPE_CANCELLATION = 1
+TYPE_TEACHER_CANCELLATION = 2
+TYPE_CORRIDOR = 3
+
+
+def parse_type_of_untis_flags(flags):
+    type_ = TYPE_SUBSTITUTION
+    if "E" in flags:
+        type_ = TYPE_CANCELLATION
+    elif "F" in flags:
+        type_ = TYPE_TEACHER_CANCELLATION
+    return type_
+
+
+drive = build_drive()
+
+
+class Substitution(object):
+    def __init__(self):
+        self.filled = False
+        self.id = None
+        self.lesson_id = None
+        self.date = None
+        self.lesson = None
+        self.type = None
+        self.text = None
+        self.teacher_old = None
+        self.teacher_new = None
+        self.subject_old = None
+        self.subject_new = None
+        self.room_old = None
+        self.room_new = None
+        self.corridor = None
+        self.classes = None
+        self.lesson_element = None
+
+    def __str__(self):
+        if self.filled:
+            return self.id
+        else:
+            return "Unbekannt"
+
+    def create(self, db_obj):
+        self.filled = True
+        self.id = db_obj.substitution_id
+        self.lesson_id = db_obj.lesson_idsubst
+        self.date = untis_date_to_date(db_obj.date)
+        self.lesson = db_obj.lesson
+        self.type = parse_type_of_untis_flags(db_obj.flags)
+        self.text = db_obj.text
+
+        # Lesson
+
+        # Teacher
+        # print(db_obj.teacher_idlessn)
+        if db_obj.teacher_idlessn != 0:
+            self.teacher_old = drive["teachers"][db_obj.teacher_idlessn]
+        if db_obj.teacher_idsubst != 0:
+            self.teacher_new = drive["teachers"][db_obj.teacher_idsubst]
+
+            if self.teacher_old is not None and self.teacher_new.id == self.teacher_old.id:
+                self.teacher_new = None
+
+        self.lesson_element = get_lesson_element_by_id_and_teacher(self.lesson_id, self.teacher_old)
+        # print(self.lesson)
+
+        # Subject
+        self.subject_old = self.lesson_element.subject if self.lesson_element is not None else None
+        if db_obj.subject_idsubst != 0:
+            self.subject_new = drive["subjects"][db_obj.subject_idsubst]
+
+            if self.subject_old is not None and self.subject_old.id == self.subject_new.id:
+                self.subject_new = None
+
+        # Room
+        self.rooms_old = self.lesson_element.rooms if self.lesson_element is not None else []
+        if len(self.rooms_old) >= 1:
+            self.room_old = self.rooms_old[0]
+
+        if db_obj.room_idsubst != 0:
+            self.room_new = drive["rooms"][db_obj.room_idsubst]
+
+            if self.room_old is not None and self.room_old.id == self.room_new.id:
+                self.room_new = None
+        # if self.rooms_old
+
+        # print(self.room_new)
+        # print("CORRIDOR")
+        # print(self.corridor)
+        if db_obj.corridor_id != 0:
+            self.corridor = drive["corridors"][db_obj.corridor_id]
+            self.type = TYPE_CORRIDOR
+        # Classes
+
+        self.classes = []
+        class_ids = untis_split_first(db_obj.classids, conv=int)
+        # print(class_ids)
+        for id in class_ids:
+            self.classes.append(drive["classes"][id])
+
+
+def substitutions_sorter(sub):
+    # First, sort by class
+    sort_by = "".join(class_.name for class_ in sub.classes)
+
+    # If the sub hasn't got a class, then put it to the bottom
+    if sort_by == "":
+        sort_by = "Z"
+
+    # Second, sort by lesson number
+    sort_by += str(sub.lesson)
+
+    return sort_by
+
+
+class SubRow(object):
+    def __init__(self):
+        self.color = "black"
+        self.css_class = "black-text"
+        self.lesson = ""
+        self.classes = ""
+        self.teacher = ""
+        self.teacher_full = ""
+        self.subject = ""
+        self.subject_full = ""
+        self.room = ""
+        self.room_full = ""
+        self.text = ""
+        self.extra = ""
+
+
+def generate_teacher_row(sub, full=False):
+    if sub.type == 1:
+        teacher = "<s>{}</s>".format(sub.teacher_old.shortcode if not full else sub.teacher_old.name)
+
+    elif sub.teacher_new and sub.teacher_old:
+        teacher = "<s>{}</s> → <strong>{}</strong>".format(
+            sub.teacher_old.shortcode if not full else sub.teacher_old.name,
+            sub.teacher_new.shortcode if not full else sub.teacher_new.name)
+    elif sub.teacher_new and not sub.teacher_old:
+        teacher = "<strong>{}</strong>".format(sub.teacher_new.shortcode if not full else sub.teacher_new.name)
+    else:
+        teacher = "<strong>{}</strong>".format(sub.teacher_old.shortcode if not full else sub.teacher_old.name)
+
+    return teacher
+
+
+def generate_subject_row(sub, full=False):
+    if sub.type == 3:
+        subject = "Aufsicht"
+    elif sub.type == 1 or sub.type == 2:
+        subject = "<s>{}</s>".format(sub.subject_old.shortcode if not full else sub.subject_old.name)
+    elif sub.subject_new and sub.subject_old:
+        subject = "<s>{}</s> → <strong>{}</strong>".format(
+            sub.subject_old.shortcode if not full else sub.subject_old.name,
+            sub.subject_new.shortcode if not full else sub.subject_new.name)
+    elif sub.subject_new and not sub.subject_old:
+        subject = "<strong>{}</strong>".format(sub.subject_new.shortcode if not full else sub.subject_new.name)
+    else:
+        subject = "<strong>{}</strong>".format(sub.subject_old.shortcode if not full else sub.subject_old.name)
+
+    return subject
+
+
+def generate_room_row(sub, full=False):
+    room = ""
+    if sub.type == 3:
+        room = sub.corridor.name
+    elif sub.type == 1 or sub.type == 2:
+        pass
+    elif sub.room_new and sub.room_old:
+        room = "<s>{}</s> → <strong>{}</strong>".format(sub.room_old.shortcode if not full else sub.room_old.name,
+                                                        sub.room_new.shortcode if not full else sub.room_new.name)
+    elif sub.room_new and not sub.room_old:
+        room = sub.room_new.shortcode if not full else sub.room_new.name
+    elif not sub.room_new and not sub.room_old:
+        pass
+    else:
+        room = sub.room_old.shortcode if not full else sub.room_old.name
+
+    return room
+
+
+def generate_sub_table(subs):
+    sub_rows = []
+    for sub in subs:
+        sub_row = SubRow()
+
+        sub_row.color = "black"
+        if sub.type == 1 or sub.type == 2:
+            sub_row.css_class = "green-text"
+            sub_row.color = "green"
+        elif sub.type == 3:
+            sub_row.css_class = "blue-text"
+            sub_row.color = "blue"
+
+        if sub.type == 3:
+            sub_row.lesson = "{}./{}".format(sub.lesson - 1, sub.lesson)
+        else:
+            sub_row.lesson = "{}.".format(sub.lesson)
+
+        for class_ in sub.classes:
+            sub_row.classes = class_.name
+
+        sub_row.teacher = generate_teacher_row(sub)
+        sub_row.teacher_full = generate_teacher_row(sub, full=True)
+        sub_row.subject = generate_subject_row(sub)
+        sub_row.subject_full = generate_subject_row(sub, full=True)
+        sub_row.room = generate_room_row(sub)
+        sub_row.room_full = generate_room_row(sub, full=True)
+
+        sub_row.text = sub.text
+
+        sub_row.badge = None
+        if sub.type == 1:
+            sub_row.badge = "Schüler frei"
+        elif sub.type == 2:
+            sub_row.badge = "Lehrer frei"
+
+        sub_row.extra = "{} {}".format(sub.id, sub.lesson_id)
+
+        sub_rows.append(sub_row)
+    return sub_rows
+
+
+def get_substitutions_by_date(date):
+    subs_raw = run_default_filter(
+        run_using(models.Substitution.objects.filter(date=date_to_untis_date(date)).order_by("classids", "lesson")),
+        filter_term=False)
+    # print(subs_raw)
+
+    subs = row_by_row_helper(subs_raw, Substitution)
+    # print(subs)
+    # for row in subs:
+    #     print(row.classes)
+    #     for class_ in row.classes:
+    #         print(class_.name)
+    subs.sort(key=substitutions_sorter)
+    return subs