package io.gitlab.jfronny.ImgJava.util;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * Die Klasse Table vereinfacht den Zugriff auf CSV-Dateien.
 * Die Klassen Table und TableRow ermöglichen einen einfachen Zugriff auf tabellenbasierte
 * Dokumente.
 *
 * @author Thomas Schaller
 * @version 1.0 vom 01.02.2019
 */
public class Table {
    // Standardtrennzeichen für Spalten
    private static final char DEFAULT_SEPARATOR = ';';
    // Standardmarkierung für Texte
    private static final char DEFAULT_QUOTE = '"';
    // Standardtrennzeichen für Dezimalzahlen
    private static final char DEFAULT_COMMA = ',';

    // mögliche Spaltentypen
    private static final String UNKNOWN = "UNKOWN";
    private static final String INT = "INTEGER";
    private static final String DOUBLE = "DOUBLE";
    private static final String FLOAT = "FLOAT";

    // interne Verwaltung des Dokuments als JDOM-Document-Objekt
    private Document doc;
    // Verweis auf Element für Kopfzeile
    private Element header;
    // Ende Attribute

    /**
     * Erzeugt leeres Tabellen-Dokument.
     */
    public Table() {
        this.doc = new Document();
        doc.setRootElement(new Element("CSV-Data"));
        this.header = new Element("Header");
        doc.getRootElement().addContent(header);
    }


    /**
     * Erzeugt Tabellen-Dokument aus einer CSV-Datei.
     * Liest den Inhalt einer Datei und erstellt ein Tabellenobjekt mit seinen Werten. 
     * Wenn die Datei eine Kopfzeile enthält, fügen Sie "header" in den Parameter options ein. Wenn die Datei keine Kopfzeile hat, 
     * dann lassen Sie einfach die Option "header" weg.
     * @param file Dateiname der CSV-Datei.
     * @param options Geben Sie hier "header" an, wenn die Datei eine Kopfzeile enthält.
     * @param separator Trennzeichen für Spalten (meist ';' oder ',' oder '\t' für Tab)
     * @param quote Kennung für Texte (meist '"'). 
     */
    public Table(Path file, String options, char separator, char quote) throws IOException {
        loadCSV(file, options, separator, quote);
    }

    /**
     * Erzeugt Tabellen-Dokument aus einer CSV-Datei.
     * Liest den Inhalt einer Datei und erstellt ein Tabellenobjekt mit seinen Werten (Separator = ';', Kennung für Text = '"'). 
     * Wenn die Datei eine Kopfzeile enthält, fügen Sie "header" in den Parameter options ein. Wenn die Datei keine Kopfzeile hat, 
     * dann lassen Sie einfach die Option "header" weg.
     * @param file Dateiname der CSV-Datei.
     * @param options Geben Sie hier "header" an, wenn die Datei eine Kopfzeile enthält.
     */
    public Table(Path file, String options) throws IOException {
        loadCSV(file, options);
    }

    /**
     * Erzeugt Tabellen-Dokument aus einer CSV-Datei.
     * Liest den Inhalt einer Datei ohne Kopfzeile und erstellt ein Tabellenobjekt mit seinen Werten (Separator = ';', Kennung für Text = '"'). 
     * @param file Dateiname der CSV-Datei.
     */
    public Table(Path file) throws IOException {
        loadCSV(file);
    }

    // Anfang Methoden

    /**
     * Liest den Inhalt einer CSV-Datei ohne Kopfzeile (Separator = ';', Kennung für Text = '"'). 
     * @param file Dateiname der CSV-Datei.
     */
    public void loadCSV(Path file) throws IOException {
        loadCSV(file, "");
    }

    /**
     * Liest den Inhalt einer CSV-Datei  (Separator = ';', Kennung für Text = '"'). 
     * Wenn die Datei eine Kopfzeile enthält, fügen Sie "header" in den Parameter options ein. Wenn die Datei keine Kopfzeile hat, 
     * dann lassen Sie einfach die Option "header" weg.
     * @param file Dateiname der CSV-Datei.
     * @param options Geben Sie hier "header" an, wenn die Datei eine Kopfzeile enthält.
     */
    public void loadCSV(Path file, String options) throws IOException {
        loadCSV(file, options, DEFAULT_SEPARATOR, DEFAULT_QUOTE);
    }

    /**
     * Liest den Inhalt einer CSV-Datei.
     * Wenn die Datei eine Kopfzeile enthält, fügen Sie "header" in den Parameter options ein. Wenn die Datei keine Kopfzeile hat, 
     * dann lassen Sie einfach die Option "header" weg.
     * @param file Dateiname der CSV-Datei.
     * @param options Geben Sie hier "header" an, wenn die Datei eine Kopfzeile enthält.
     * @param separator Trennzeichen für Spalten (meist ';' oder ',' oder '\t' für Tab)
     * @param quote Kennung für Texte (meist '"'). 
     */
    public void loadCSV(Path file, String options, char separator, char quote) throws IOException {
        doc = new Document();
        doc.setRootElement(new Element("CSV-Data"));
        header = new Element("Header");
        doc.getRootElement().addContent(header);
        Scanner scanner = new Scanner(file);
        if (options.toLowerCase().contains("header") && scanner.hasNext()) {
            List<String> entries = parseLine(scanner.nextLine(), separator, quote);
            int i = 0;
            for (String s : entries) {
                Element entry = new Element("Column");
                header.addContent(entry);
                entry.setText(s);
                entry.setAttribute("type", "unknown");
                i++;
            }
        }

        List<Element> cols = header.getChildren();

        while (scanner.hasNext()) {
            Element line = new Element("Row");
            doc.getRootElement().addContent(line);
            List<String> entries = parseLine(scanner.nextLine(), separator, quote);
            int i = 0;

            for (String s : entries) {

                if (i == cols.size()) {
                    Element entry = new Element("Column");
                    entry.setAttribute("type", "unknown");
                    header.addContent(entry);
                    cols = header.getChildren();
                }

                Element entry = new Element("Entry");
                entry.setText(s);
                line.addContent(entry);
                i++;
            }
        }
        scanner.close();
    }

    /**
     * Speichert das aktuelle Dokument als CSV-Datei ohne Kopfzeile (Separator = ';', Kennung für Text = '"'). 
     * @param file Dateiname der CSV-Datei.
     */
    public void saveCSV(Path file) throws IOException {
        saveCSV(file, "");
    }

    /**
     * Speichert das aktuelle Dokument als CSV-Datei (Separator = ';', Kennung für Text = '"'). 
     * Wenn die Datei eine Kopfzeile enthalten, fügen Sie "header" in den Parameter options ein. Wenn die Datei keine Kopfzeile haben soll, 
     * dann lassen Sie einfach die Option "header" weg.
     * @param options Geben Sie hier "header" an, wenn die Datei eine Kopfzeile haben soll.
     * @param file Dateiname der CSV-Datei.
     */
    public void saveCSV(Path file, String options) throws IOException {
        saveCSV(file, options, DEFAULT_SEPARATOR, DEFAULT_QUOTE);
    }

    /**
     * Speichert das aktuelle Dokument als CSV-Datei. 
     * Wenn die Datei eine Kopfzeile enthalten, fügen Sie "header" in den Parameter options ein. Wenn die Datei keine Kopfzeile haben soll, 
     * dann lassen Sie einfach die Option "header" weg.
     * @param options Geben Sie hier "header" an, wenn die Datei eine Kopfzeile haben soll.
     * @param file Dateiname der CSV-Datei.
     * @param separator Trennzeichen für Spalten (meist ';' oder ',' oder '\t' für Tab)
     * @param quote Kennung für Texte (meist '"'). 
     */
    public void saveCSV(Path file, String options, char separator, char quote) throws IOException {
        PrintStream outputFile = new PrintStream(Files.newOutputStream(file));
        System.out.println("Speicher in : " + file.toAbsolutePath());
        List<Element> columns = header.getChildren();
        String sq = "" + quote;
        String ss = "" + separator;
        if (quote == '"') sq = "\"";
        if (separator == '"') ss = "\"";

        if (options.toLowerCase().contains("header")) {
            String h = "";
            for (Element c : columns) {
                h += ss + sq + c.getText() + sq;
            }
            outputFile.println(h.substring(1));
        }
        for (int i = 0; i < getRowCount(); i++) {
            String l = "";
            for (String s : getStringRow(i)) {

                if (s.contains("" + separator)) {
                    if (quote == '"' && s.contains("\"")) {
                        s = s.replace("\"", "\"\"");
                    }
                    l += ss + sq + s + sq;
                } else {
                    l += ss + s;
                }

            }
            outputFile.println(l.substring(1));
        }
        outputFile.close();
    }

    /** Speichert die Tabelle als XML-Dokument.
     *  @param file Dateiname des XML-Files
     */
    public void saveXML(Path file) throws IOException {
        // new XMLOutputter().output(doc, System.out);
        XMLOutputter xmlOutput = new XMLOutputter();

        // display nice nice
        xmlOutput.setFormat(Format.getPrettyFormat());
        OutputStream outputFile = Files.newOutputStream(file);
        System.out.println("Speicher in : " + file.toAbsolutePath());
        xmlOutput.output(doc, outputFile);
        outputFile.close();
        System.out.println("File Saved!");
    }

    //----------------------------------------------- Zeigerbewegungen --------------------------------------------------

    /** HIlfsfunktion für die Analyse einer Dateizeile
     * @param cvsLine Zeile aus der Datei
     * @return Liste von String für die einzelnen Spalten
     */
    private List<String> parseLine(String cvsLine) {
        return parseLine(cvsLine, DEFAULT_SEPARATOR, DEFAULT_QUOTE);
    }

    /** HIlfsfunktion für die Analyse einer Dateizeile
     * @param cvsLine Zeile aus der Datei
     * @param separator Trennzeichen für die Spalten
     * @return Liste von String für die einzelnen Spalten
     */
    private List<String> parseLine(String cvsLine, char separator) {
        return parseLine(cvsLine, separator, DEFAULT_QUOTE);
    }

    /** HIlfsfunktion für die Analyse einer Dateizeile
     * @param cvsLine Zeile aus der Datei
     * @param separator Trennzeichen für die Spalten
     * @param customQuote Kennung für Strings
     * @return Liste von String für die einzelnen Spalten
     */
    private List<String> parseLine(String cvsLine, char separator, char customQuote) {

        List<String> result = new ArrayList<>();

        //if empty, return!
        if (cvsLine == null && cvsLine.isEmpty()) {
            return result;
        }

        //ggf. Default-Value laden
        if (customQuote == ' ') {
            customQuote = DEFAULT_QUOTE;
        }

        if (separator == ' ') {
            separator = DEFAULT_SEPARATOR;
        }

        StringBuffer curVal = new StringBuffer();
        boolean inQuotes = false;
        boolean startCollectChar = false;
        boolean doubleQuotesInColumn = false;

        char[] chars = cvsLine.toCharArray();

        for (char ch : chars) {

            if (inQuotes) {   // aktueller Text ist in Quotes eingeschlossen
                startCollectChar = true;

                if (ch == customQuote) {  // Quotes werden beendet, aber Achtung bei "" => Metazeichen
                    inQuotes = false;
                    if (ch == '\"') {
                        doubleQuotesInColumn = true;
                    }

                } else {

                    if (ch == '\"' && !doubleQuotesInColumn) {
                        doubleQuotesInColumn = true;
                    } else {
                        curVal.append(ch);
                        doubleQuotesInColumn = false;
                    }

                }
            } else {
                if (ch == customQuote) {

                    inQuotes = true;

                    //Fixed : allow "" in empty quote enclosed
                    if (ch == '\"') {
                        if (doubleQuotesInColumn) {
                            curVal.append('"');
                            doubleQuotesInColumn = false;
                        } else doubleQuotesInColumn = true;


                    }
                } else {
                    doubleQuotesInColumn = false;
                    if (ch == separator) {

                        result.add(curVal.toString());

                        curVal = new StringBuffer();
                        startCollectChar = false;

                    } else if (ch == '\r') {
                        //ignore LF characters
                        continue;
                    } else if (ch == '\n') {
                        //the end, break!
                        break;
                    } else {
                        curVal.append(ch);
                    }
                }
            }

        }
        result.add(curVal.toString());
        return result;
    }

    /**
     *  Sucht die Nummer einer durch Namen gegebenen Spalte.
     *  @param name Name der Spalte
     *  @return Nummer der Spalte
     */

    private int findColumnNumber(String name) {
        List<Element> columns = header.getChildren();
        int i = 0;
        for (Element c : columns) {
            if (c.getText().equalsIgnoreCase(name)) {
                return i;

            }
            i++;
        }
        return -1;
    }

    /**
     * Fügt eine neue Spalte am Ende der Tabelle an.
     */
    public void addColumn() {
        Element entry = new Element("Column");
        entry.setAttribute("type", Table.UNKNOWN);
        header.addContent(entry);
    }

    /**
     * Fügt eine neue Spalte am Ende der Tabelle an und benennt sie.
     * @param title Bezeichnung der Spalte
     */
    public void addColumn(String title) {
        addColumn();
        Element nc = ((List<Element>) (header.getChildren())).get(header.getChildren().size() - 1);
        nc.setText(title);
    }

    /**
     * Fügt eine neue Spalte am Ende der Tabelle an und benennt und typisiert sie.
     * @param title Bezeichnung der Spalte
     * @param type Typ der Spalte (UNKNOWN, DOUBLE, INTEGER, FLOAT)
     */
    public void addColumn(String title, String type) {
        addColumn(title);
        Element nc = ((List<Element>) (header.getChildren())).get(header.getChildren().size() - 1);
        nc.setAttribute("type", type);
    }

    /**
     * Löscht eine Spalte.
     * @param i Nummer der Spalte.
     */
    public void removeColumn(int i) {
        List<Element> lines = doc.getRootElement().getChildren();
        for (Element l : lines) {
            if (l.getChildren().size() > i) l.removeContent(i);
        }
    }

    /**
     * Löscht eine Spalte
     * @param name Name der Spalte
     */
    public void removeColumn(String name) {
        removeColumn(findColumnNumber(name));
    }

    /**
     * Liefert die Anzahl der Spalten in der Tabelle
     * @return Anzahl der Spalten
     */
    public int getColumnCount() {
        return header.getChildren().size();
    }

    /**
     * Liefert die Anzahl der Zeilen in der Tabelle
     * @return Anzahl der Zeilen
     */
    public int getRowCount() {
        return doc.getRootElement().getChildren().size() - 1;
    }

    /**
     * Löscht alle Zeilen der Tabelle.
     * Die Spaltenüberschriften und Typen bleiben erhalten.
     */
    public void clearRows() {
        doc.getRootElement().removeChildren("Row");
    }

    /**
     * Fügt eine neue Zeile an das Ende der Tabelle an.
     * @return ein TableRow-Objekt für diese neue Zeile
     */
    public TableRow addRow() {
        Element row = new Element("Row");
        doc.getRootElement().addContent(row);
        return new TableRow(doc, row);
    }

    /**
     * Löscht eine Zeile
     * @param i Nummer der Zeile
     */
    public void removeRow(int i) {
        if (i < getRowCount()) {
            doc.getRootElement().removeContent(i);
        }
    }

    /**
     * Liefert eine Zeile der Tabelle
     * @param i Nummer der Zeile
     * @return TableRow-Objekt für diese Zeile
     */
    public TableRow getRow(int i) {
        if (i < getRowCount()) {
            List<Element> rows = doc.getRootElement().getChildren();
            return new TableRow(doc, rows.get(i + 1));
        }
        return null;
    }

    /**
     * Liefert die ganze Tabelle als Array von TableRow-Objekten
     * @return Array von TableRow-Objekten
     */
    public TableRow[] rows() {
        TableRow[] rows = new TableRow[getRowCount()];
        for (int i = 0; i < getRowCount(); i++) {
            rows[i] = getRow(i);
        }
        return rows;
    }

    /**
     * Liefert den Wert einer Zelle als Integer-Zahl
     * @param row Zeilennummer
     * @param column Spaltennummer
     * @return Wert der Zelle
     */
    public int getInt(int row, int column) {
        return getRow(row).getInt(column);
    }

    /**
     * Liefert den Wert einer Zelle als Integer-Zahl
     * @param row Zeilennummer
     * @param name Name der Spalte
     * @return Wert der Zelle
     */
    public int getInt(int row, String name) {
        return getRow(row).getInt(name);
    }

    /**
     * Setzt den Wert einer Zelle als Integer-Zahl
     * @param row Zeilennummer
     * @param column Spaltennummer
     * @param value neuer Wert der Zelle
     */
    public void setInt(int row, int column, int value) {
        getRow(row).setInt(column, value);
    }

    /**
     * Setzt den Wert einer Zelle als Integer-Zahl
     * @param row Zeilennummer
     * @param name Name der Spalte
     * @param value neuer Wert der Zelle
     */
    public void setInt(int row, String name, int value) {
        getRow(row).setInt(name, value);
    }

    /**
     * Liefert alle Werte einer Zeile als Integer-Array.
     * @param row Nummer der Zeile
     * @return int-Array, dass alle Werte der Zeile enthält
     */
    public int[] getIntRow(int row) {
        try {
            TableRow trow = getRow(row);
            int anz = getColumnCount();
            int[] r = new int[anz];
            for (int i = 0; i < anz; i++) {
                r[i] = trow.getInt(i);
            }
            return r;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Liefert alle Werte einer Spalte als Integer-Array.
     * @param column Nummer der Spalte
     * @return int-Array, dass alle Werte der Spalte enthält
     */
    public int[] getIntColumn(int column) {
        try {
            int anz = getRowCount();
            int[] r = new int[anz];
            for (int i = 0; i < anz; i++) {
                r[i] = getInt(i, column);
            }
            return r;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Liefert alle Werte einer Spalte als Integer-Array.
     * @param name Name der Spalte
     * @return int-Array, dass alle Werte der Spalte enthält
     */
    public int[] getIntColumn(String name) {
        return getIntColumn(findColumnNumber(name));
    }


    /**
     * Liefert den Wert einer Zelle als Float-Zahl
     * @param row Zeilennummer
     * @param column Spaltennummer
     * @return Wert der Zelle
     */
    public float getFloat(int row, int column) {
        return getRow(row).getFloat(column);
    }

    /**
     * Liefert den Wert einer Zelle als Float-Zahl
     * @param row Zeilennummer
     * @param name Name der Spalte
     * @return Wert der Zelle
     */
    public float getFloat(int row, String name) {
        return getRow(row).getFloat(name);
    }

    /**
     * Setzt den Wert einer Zelle als Float-Zahl
     * @param row Zeilennummer
     * @param column Spaltennummer
     * @param value neuer Wert der Zelle
     */
    public void setFloat(int row, int column, float value) {
        getRow(row).setFloat(column, value);
    }

    /**
     * Setzt den Wert einer Zelle als Float-Zahl
     * @param row Zeilennummer
     * @param name Name der Spalte
     * @param value neuer Wert der Zelle
     */
    public void setFloat(int row, String name, float value) {
        getRow(row).setFloat(name, value);
    }

    /**
     * Liefert alle Werte einer Zeile als Float-Array.
     * @param row Nummer der Zeile
     * @return int-Array, dass alle Werte der Zeile enthält
     */
    public float[] getFloatRow(int row) {
        try {
            TableRow trow = getRow(row);
            int anz = getColumnCount();
            float[] r = new float[anz];
            for (int i = 0; i < anz; i++) {
                r[i] = trow.getFloat(i);
            }
            return r;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Liefert alle Werte einer Spalte als Float-Array.
     * @param column Nummer der Spalte
     * @return int-Array, dass alle Werte der Spalte enthält
     */
    public float[] getFloatColumn(int column) {
        try {
            int anz = getRowCount();
            float[] r = new float[anz];
            for (int i = 0; i < anz; i++) {
                r[i] = getFloat(i, column);
            }
            return r;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Liefert alle Werte einer Spalte als Float-Array.
     * @param name Name der Spalte
     * @return int-Array, dass alle Werte der Spalte enthält
     */
    public float[] getFloatColumn(String name) {
        return getFloatColumn(findColumnNumber(name));
    }

    /**
     * Liefert den Wert einer Zelle als Double-Zahl
     * @param row Zeilennummer
     * @param column Spaltennummer
     * @return Wert der Zelle
     */
    public double getDouble(int row, int column) {
        return getRow(row).getDouble(column);
    }

    /**
     * Liefert den Wert einer Zelle als Double-Zahl
     * @param row Zeilennummer
     * @param name Name der Spalte
     * @return Wert der Zelle
     */
    public double getDouble(int row, String name) {
        return getRow(row).getDouble(name);
    }

    /**
     * Setzt den Wert einer Zelle als Double-Zahl
     * @param row Zeilennummer
     * @param column Spaltennummer
     * @param value neuer Wert der Zelle
     */
    public void setDouble(int row, int column, double value) {
        getRow(row).setDouble(column, value);
    }

    /**
     * Setzt den Wert einer Zelle als Double-Zahl
     * @param row Zeilennummer
     * @param name Name der Spalte
     * @param value neuer Wert der Zelle
     */
    public void setDouble(int row, String name, double value) {
        getRow(row).setDouble(name, value);
    }

    /**
     * Liefert alle Werte einer Spalte als Double-Array.
     * @param row Nummer der Spalte
     * @return int-Array, dass alle Werte der Spalte enthält
     */
    public double[] getDoubleRow(int row) {
        try {
            TableRow trow = getRow(row);
            int anz = getColumnCount();
            double[] r = new double[anz];
            for (int i = 0; i < anz; i++) {
                r[i] = trow.getDouble(i);
            }
            return r;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Liefert alle Werte einer Spalte als Double-Array.
     * @param column Nummer der Spalte
     * @return int-Array, dass alle Werte der Spalte enthält
     */
    public double[] getDoubleColumn(int column) {
        try {
            int anz = getRowCount();
            double[] r = new double[anz];
            for (int i = 0; i < anz; i++) {
                r[i] = getDouble(i, column);
            }
            return r;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Liefert alle Werte einer Spalte als Double-Array.
     * @param name Name der Spalte
     * @return int-Array, dass alle Werte der Spalte enthält
     */
    public double[] getDoubleColumn(String name) {
        return getDoubleColumn(findColumnNumber(name));
    }

    /**
     * Liefert den Wert einer Zelle als String
     * @param row Zeilennummer
     * @param column Spaltennummer
     * @return Wert der Zelle
     */
    public String getString(int row, int column) {
        return getRow(row).getString(column);
    }

    /**
     * Liefert den Wert einer Zelle als String
     * @param row Zeilennummer
     * @param name Name der Spalte
     * @return Wert der Zelle
     */
    public String getString(int row, String name) {
        return getRow(row).getString(name);
    }

    /**
     * Setzt den Wert einer Zelle als String
     * @param row Zeilennummer
     * @param column Spaltennummer
     * @param text neuer Wert der Zelle
     */
    public void setString(int row, int column, String text) {
        getRow(row).setString(column, text);
    }

    /**
     * Setzt den Wert einer Zelle als String
     * @param row Zeilennummer
     * @param name Name der Spalte
     * @param text neuer Wert der Zelle
     */
    public void setString(int row, String name, String text) {
        getRow(row).setString(name, text);
    }

    /**
     * Liefert alle Werte einer Spalte als String-Array.
     * @param row Nummer der Spalte
     * @return int-Array, dass alle Werte der Spalte enthält
     */
    public String[] getStringRow(int row) {
        try {
            TableRow trow = getRow(row);
            int anz = getColumnCount();
            String[] r = new String[anz];
            for (int i = 0; i < anz; i++) {
                r[i] = trow.getString(i);
            }
            return r;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Liefert alle Werte einer Spalte als String-Array.
     * @param column Nummer der Spalte
     * @return int-Array, dass alle Werte der Spalte enthält
     */
    public String[] getStringColumn(int column) {
        try {
            int anz = getRowCount();
            String[] r = new String[anz];
            for (int i = 0; i < anz; i++) {
                r[i] = getString(i, column);
            }
            return r;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Liefert alle Werte einer Spalte als String-Array.
     * @param name Name der Spalte
     * @return int-Array, dass alle Werte der Spalte enthält
     */
    public String[] getStringColumn(String name) {
        return getStringColumn(findColumnNumber(name));
    }


    /**
     * Sucht nach einem bestimmtem Wert in einer Zeile.
     * @param value Wert der gesucht werden soll
     * @param column Nummer der Spalte, die durchsucht werden soll
     * @return TableRow-Objekt der Zeile, wenn der Wert gefunden wurde, sonst null
     */
    public TableRow findRow(String value, int column) {
        for (int i = 0; i < getRowCount(); i++) {
            if (getString(i, column).equals(value)) {
                return getRow(i);
            }
        }
        return null;
    }

    /**
     * Sucht nach einem bestimmtem Wert in einer Zeile.
     * @param value Wert der gesucht werden soll
     * @param name Name der Spalte, die durchsucht werden soll
     * @return TableRow-Objekt der Zeile, wenn der Wert gefunden wurde, sonst null
     */
    public TableRow findRow(String value, String name) {
        return findRow(value, findColumnNumber(name));
    }

    /**
     * Kürzt alle Einträge der Tabelle um unnötige Leerzeichen am Anfang oder Ende
     */
    public void trim() {
        for (int y = 0; y < getRowCount(); y++) {
            for (int x = 0; x < getColumnCount(); x++) {
                setString(y, x, getString(y, x).trim());
            }
        }
    }
}
