diff --git a/umbra/controller.py b/umbra/controller.py
index 9716d29d1a03886a8ca3d2d2b3d204923bbf56ac..b4f63999b52aa9c198b7b4ade7c06348e2547784 100644
--- a/umbra/controller.py
+++ b/umbra/controller.py
@@ -1,5 +1,5 @@
-from filereader import FileReader, CSVReader, TxtReader  # , FileWriter
-# Disabled the FileWriter import since it does not exist yet.
+from filereader import FileReader, CSVReader, TxtReader
+from filereader import FileWriter, CSVWriter, TxtWriter
 
 
 class Controller:
@@ -11,8 +11,9 @@ class Controller:
         self._model = model
         self._view = view
         self._view.actionlistener = self.actionlistener
-        self._filereader = CSVReader(None, None)  # TODO: Deal with csv OR txt
-        # self._filewriter = FileWriter()
+
+        self._filereader = CSVReader("","")  # TODO: Deal with csv OR txt
+        self._filewriter = CSVWriter()
 
         # Lists of paths, represented as string
         self._source_files = []
@@ -38,6 +39,11 @@ class Controller:
             self._compare_files()
         elif action == 'save':
             self._save_results()
+        elif action == 'save_csv':
+            self._filewriter = CSVWriter()
+        elif action == 'save_txt':
+            self._filewriter = TxtWriter()
+
 
     def _select_files(self, type):
         """Select files and add them to files list corresponding to type.
@@ -73,7 +79,8 @@ class Controller:
             self._view.update_message('no shadow')
         else:
             self._view.update_message('files ok')
-            self._read_files(None)  # TODO: Adapt to future implementation
+            self._read_files("source") 
+            self._read_files("shadow")
             self._model.compare()
             self._view.update_message('comparison complete')
 
@@ -83,8 +90,9 @@ class Controller:
             self._view.update_message('no comparison')
         else:
             path = self._view.ask_save_location()
-            results = self._model.results  # TODO: Check exact syntax when implemented
+            results = self._model._analysis_results
             self._filewriter.write(path, results)
+            # results are of form sc, sh, info
             self._view.update_message('saved')
 
     def _read_files(self, type):
@@ -94,12 +102,12 @@ class Controller:
             type (str): Role of file ('source' or 'shadow')
         """
         # TODO
-        # data = filereader.read(path, type)
-        # data_property = getattr(self._model, 'data_{}'.format(type))
-        # data_property(data)
-
         # Temporary 'solution' for testing below
-        self._filereader = CSVReader(self._source_files[0],
-                                     self._shadow_files[0])
-        self._model.data_source, self._model.data_shadow =\
-            self._filereader.read()
+        path = self._source_files[0]
+        print(path)
+        self._filereader = CSVReader(path, type)
+        data = self._filereader.read()
+        if type == "source": # Fix is dirtier than I can talk
+            self._model._data_source = data
+        else:
+            self._model._data_shadow = data
diff --git a/umbra/filereader.py b/umbra/filereader.py
index fff52920865d7870b53e86ca4257e075208c184f..a74e0c063349a6f6804c2c1bc815ae16d78a7178 100644
--- a/umbra/filereader.py
+++ b/umbra/filereader.py
@@ -1,6 +1,8 @@
 import pandas as pd
+import numpy as np
 from abc import ABC, abstractmethod
 from words import SourceWord, ShadowWord, Sentence
+import csv
 
 
 class FileReader (ABC):
@@ -36,65 +38,154 @@ class FileReader (ABC):
             kind of word it should be converted.
 
         Returns:
-            words: list of the created Word instances.
+            words: type Sentence, object containing list of words.
         """
-        words = []
+        ws = []
         for row in df.itertuples(name="Words"):
             if word_type == "source":
                 word = SourceWord(row.Word.lower(), row.Onset, row.Offset)
             else:
                 word = ShadowWord(row.Word.lower(), row.Onset, row.Offset)
-            words.append(word)
+            ws.append(word)
+            words = Sentence(ws)
         return words
 
 
 class CSVReader(FileReader):
 
-    def __init__(self, path_source, path_shadow):
-        """Constructor
-
+    def __init__(self, path, type):
+        """
         Args:
-            path_source: the internal path to the source file
-            path_shadow: the internal path to the shadow file
+            path: string, the internal path to the source file
         """
-        self._path_source = path_source
-        self._path_shadow = path_shadow
+        self._path = path
+        self._type = type  # Very dirty fix
 
     def read(self):
         """Method that is used to read the data into a workable format"""
-        source_df = pd.read_csv(self._path_source, header=None, sep='\n')
-        source_df = source_df[0].str.split('\t', expand=True)
-        shadow_df = pd.read_csv(self._path_shadow, header=None, sep='\n')
-        shadow_df = shadow_df[0].str.split('\t', expand=True)
-        source_df = self.extract_task_data(source_df)
-        shadow_df = self.extract_task_data(shadow_df)
-        source_words = Sentence(self.df_to_words(source_df, "source"))
-        shadow_words = Sentence(self.df_to_words(shadow_df, "shadow"))
-        return source_words, shadow_words
+        df = pd.read_csv(self._path, header=None, sep='\n')
+        df = df[0].str.split('\t', expand=True)
+        data = self.extract_task_data(df)
+        words = self.df_to_words(data, self._type)
+        return words
 
 
 class TxtReader(FileReader):
 
-    def __init__(self, path_source, path_shadow):
+    def __init__(self, path):
         """Constructor
 
         Args:
-            path_source: the internal path to the source file
-            path_shadow: the internal path to the shadow file
+            path: path to file
         """
-        self._path_source = path_source
-        self._path_shadow = path_shadow
+        self._path = path
+        self._words = None
 
     def read(self):
-        """Method that is used to read the data into a workable format"""
-        with open(self._path_source, 'r') as source,\
-                open(self._path_shadow, 'r') as shadow:
-            # Does this even work? See warning:
-            source_df = self.extract_task_data(source)
-            shadow_df = self.extract_task_data(shadow)
-            source_words = Sentence(self.df_to_words(source_df,
-                                                     "source"))
-            shadow_words = Sentence(self.df_to_words(shadow_df,
-                                                     "shadow"))
-        return source_words, shadow_words
+        """
+        Read data into Sentences.
+        Returns:
+            words: Sentence containing Words.
+        """
+        with open(self._path, 'r') as data:
+            self._words = self.extract_task_data(data)
+            self._words = self.df_to_words(self._words, "header")
+            return self._words
 
+
+class FileWriter(ABC):
+    def __init__(self):
+        pass
+
+    @abstractmethod
+    def write(self):
+        pass
+
+    def write_per_part(self):
+        """
+        Write result per participant.
+        """
+        for pn, pr in self.data:
+            results, stats = _format_results(pn, pr)
+            self.path = _participant_path(pn)
+            self.write()
+
+    @abstractmethod
+    def _participant_path(self, number):
+        pass
+
+
+class TxtWriter(FileWriter):
+    def __init__(self):
+        super().__init__()
+
+    def write(self, path, results):
+        """
+        Write a .txt file of analysis results.
+        Args:
+            path: string of paths
+            result: the results, type unknown
+        """
+        # For now assume source, shadow, stat format
+
+        source_results, shadow_results, info = results
+        final = np.empty(0)
+        for i in range(len(source_results)):
+            source_word = source_results.words[i]
+            res = (str(source_word), str(source_word.shadowed)+"\n")
+            final = np.append(final, res)
+        final = np.append(final, "Total: "+str(info[0]))
+        final = np.append(final, "Correct: "+str(info[1]))
+        final = np.append(final, "Skips: "+str(info[2]))
+        np.savetxt(path, final, fmt="%s", header="Word|Shadowed")
+
+# Untested
+    def _participant_path(part_number):
+        """
+        Create a path for the appropriate participant.
+        Args: part_number: int of participant number
+        Returns:
+            participath: string, a path towards a directory for participant
+            part_number
+        """
+        pth = self.path+"/"+part_number
+        os.mkdir(pth)
+        participath = pth+"/"+part_number+".txt"
+        return participath
+
+
+class CSVWriter(FileWriter):
+    def __init__(self):
+        super().__init__()
+
+    def write(self, path, results):
+        """
+        Write a CSV file of the results.
+        Args: path: string of path
+              results: results, type unknown
+
+        """
+        source, shadow, info = results
+        info = "Total " + str(info[0]), "Shadowed " + str(info[1]), "Skipped"\
+            " " + str(info[2])
+        sc = []
+        for entry in source.words:
+            sc.append([entry.word, entry.onset, entry.offset, entry.shadowed])
+        with open(path+'.csv', 'w') as f:
+            writer = csv.writer(f)
+            writer.writerow(["Word", "Onset", "Offset", "Shadowed"])
+            writer.writerows(sc)
+            writer.writerow(info)
+
+    # TODO: Test per-participant writing
+    def _participant_path(part_number):
+        """
+        Create a path for the appropriate participant.
+        Args: int part_number, participant number.
+        Returns:
+            participath: string, a path towards a directory for participant part_number
+        """
+        pth = self.path+"/"+part_number
+        os.mkdir(pth)
+        participath = pth+"/"+part_number
+        return participath
diff --git a/umbra/model.py b/umbra/model.py
index 47124412ec91c8bf086a65f36ed05fb4b4065436..1b1a75990a0e68237f13d479a9d321d0fd0f729c 100644
--- a/umbra/model.py
+++ b/umbra/model.py
@@ -52,5 +52,8 @@ class Model:
 
     def compare(self):
         """"Run the analyses and saves the results."""
-        self._analysis_results = self._stats.analyze(self._data_source,
+        if self.has_source() and self.has_shadow():
+            self._analysis_results = self._stats.analyze(self._data_source,
                                                      self._data_shadow)
+        else: 
+            print("This needs fixing")
diff --git a/umbra/saa_Romeo.py b/umbra/saa_Romeo.py
index 94207ed77b262a736e8be6ffd9e5c7c2f1e8b04d..6b7d87478cfe7ed0e0f037793946a4ef57900fc4 100644
--- a/umbra/saa_Romeo.py
+++ b/umbra/saa_Romeo.py
@@ -138,12 +138,9 @@ class SaaRomeo(AlignmentStrategy):
         alignment_source.reverse()
         alignment_shadow.reverse()
 
-        for source_word, shadow_word in zip(alignment_source,alignment_shadow):
+        for source_word, shadow_word in zip(alignment_source, alignment_shadow):
             if type(source_word) is not Gap and type(shadow_word) is not Gap:
                 if source_word == shadow_word:
                     source_word.shadowed = True
 
         return Sentence(alignment_source), Sentence(alignment_shadow)
-
-
-
diff --git a/umbra/view.py b/umbra/view.py
index b74c527cde3871c900b0e358991e6dc3496b9209..17d91526146e3f16b92ed1df0f25f2647a502133 100644
--- a/umbra/view.py
+++ b/umbra/view.py
@@ -56,9 +56,9 @@ class View:
 
         # TODO: Deal with multiple files at once
         for path in paths:
-            if path == "":  # Do not assign an empty file path
-                # TODO: Error message and close
-                select_files(type) #prompt again
+           if path == "":  # Do not assign an empty file path
+               # TODO: Error message and close
+               select_files(type)  # prompt again
         return paths
 
     def update_files(self, paths, type):
@@ -123,12 +123,12 @@ class View:
                           'delete shadow',
                           'compare',
                           'save',
+
                           ]
         if key in controllerkeys:
             self._actionlistener(key)
 
-    @staticmethod
-    def ask_save_location():
+    def ask_save_location(self):
         """Ask user for location to save file."""
         path = filedialog.asksaveasfilename(title="Save file",
                                             parent=self._window,
@@ -136,7 +136,7 @@ class View:
                                                        ("all files", "*.*")))
         if ".txt" not in path:
             path += ".txt"
-        if save_path == ".txt":
+        if path == ".txt":
             # TODO: Error message & close
             self.ask_save_location()  # Prompt again
         return path
@@ -271,6 +271,7 @@ class View:
         else:
             return selected
 
+
 class Options(View):
     """GUI control of program options."""
 
diff --git a/umbra/words.py b/umbra/words.py
index 4260b88cf8079214f710df1af0f1fdd7feda6433..2a9c2feb3e38c2fb2a8034f3168e9653760ede73 100644
--- a/umbra/words.py
+++ b/umbra/words.py
@@ -14,6 +14,7 @@ class Word:
     def __eq__(self, word):
         return self._word == word.word
 
+
     @property
     def word(self):
         """Getter for the word.
@@ -67,6 +68,14 @@ class Word:
         """
         self._anchor = anchor
 
+    def get_difference(self, other):
+        """Get the difference between the onset of this word and the other.
+
+        Args:
+            other: the other Word instance
+        """
+        return other.onset - self._onset
+
 
 class ShadowWord(Word):
     def __init__(self, word, onset, offset):
@@ -165,6 +174,13 @@ class SourceWord(Word):
 class Sentence(list):
     def __init__(self, words):
         list.__init__(self, words)
+        self.words = words  # I am not sure if this is the 'proper' fix
 
     def __str__(self):
-        return " ".join([str(w) for w in self])
+        return " ".join([str(w) for w in self.words])
+
+    def __len__(self):
+        return len(self.words)
+
+    def __iter__(self):
+        return iter(self.words)