diff --git a/JCash.iml b/JCash.iml
new file mode 100644
index 0000000..c90834f
--- /dev/null
+++ b/JCash.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Main.java b/src/Main.java
new file mode 100644
index 0000000..3e59c38
--- /dev/null
+++ b/src/Main.java
@@ -0,0 +1,5 @@
+public class Main {
+ public static void main(String[] args) {
+ System.out.println("Hello world!");
+ }
+}
\ No newline at end of file
diff --git a/src/me/teridax/jcash/banking/Account.java b/src/me/teridax/jcash/banking/Account.java
new file mode 100644
index 0000000..36b534a
--- /dev/null
+++ b/src/me/teridax/jcash/banking/Account.java
@@ -0,0 +1,34 @@
+package me.teridax.jcash.banking;
+
+@SuppressWarnings("unused")
+public abstract class Account {
+
+ private int iban;
+ private int pin;
+ private double balance;
+
+ private final Owner owner;
+
+ public Account(int iban, int pin, Owner owner) {
+ this.owner = owner;
+ this.iban = iban;
+ this.pin = pin;
+ this.balance = 0.0d;
+ }
+
+ public Owner getOwner() {
+ return owner;
+ }
+
+ public int getIban() {
+ return iban;
+ }
+
+ public int getPin() {
+ return pin;
+ }
+
+ public double getBalance() {
+ return balance;
+ }
+}
diff --git a/src/me/teridax/jcash/banking/Bank.java b/src/me/teridax/jcash/banking/Bank.java
new file mode 100644
index 0000000..026b5d5
--- /dev/null
+++ b/src/me/teridax/jcash/banking/Bank.java
@@ -0,0 +1,61 @@
+package me.teridax.jcash.banking;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+@SuppressWarnings("unused")
+public final class Bank {
+ private String name;
+ private int blz;
+ private List accounts;
+
+ private Bank(int blz, String name) {
+ this.blz = blz;
+ this.name = name;
+ this.accounts = new ArrayList<>();
+ }
+
+ public Account[] getAccounts() {
+ return accounts.toArray(new Account[0]);
+ }
+
+ public int getBlz() {
+ return blz;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Bank) {
+ return blz == ((Bank) obj).blz;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(blz, name);
+ }
+
+ public Account[] getAccountsOfOwner(Owner owner) {
+ return accounts.stream()
+ .filter(account -> account.getOwner().equals(owner))
+ .toArray(Account[]::new);
+ }
+
+ private static String validateBlz(String maybeBlz) {
+ var builder = new StringBuilder();
+ maybeBlz.trim().chars().filter(ch -> Character.isDigit(ch) || Character.isLetter(ch)).forEach(builder::append);
+ var blz = builder.toString();
+
+ if (blz.isEmpty()) {
+ throw new IllegalArgumentException("Bank Blz must only contain letters and digits");
+ }
+
+ return blz;
+ }
+}
diff --git a/src/me/teridax/jcash/banking/BankingManagementSystem.java b/src/me/teridax/jcash/banking/BankingManagementSystem.java
new file mode 100644
index 0000000..1cd09ae
--- /dev/null
+++ b/src/me/teridax/jcash/banking/BankingManagementSystem.java
@@ -0,0 +1,35 @@
+package me.teridax.jcash.banking;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class BankingManagementSystem {
+
+ private List banks;
+
+ private BankingManagementSystem(List banks) {
+ this.banks = banks;
+ }
+
+ public static BankingManagementSystem loadFromCsv(File file) {
+
+ try {
+ var content = Files.readString(file.toPath());
+
+ var banks = new ArrayList();
+
+ content.lines().forEach(line -> {
+ // load bank and account from line.
+ // transfer accounts to existing bank if already created
+ });
+
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Could not read file " + file);
+ }
+
+ return null;
+ }
+}
diff --git a/src/me/teridax/jcash/banking/Girokonto.java b/src/me/teridax/jcash/banking/Girokonto.java
new file mode 100644
index 0000000..68ba9f5
--- /dev/null
+++ b/src/me/teridax/jcash/banking/Girokonto.java
@@ -0,0 +1,15 @@
+package me.teridax.jcash.banking;
+
+public class Girokonto extends Account {
+
+ private double overdraft;
+
+ public Girokonto(int iban, int pin, double overdraft, Owner owner) {
+ super(iban, pin, owner);
+ this.overdraft = overdraft;
+ }
+
+ public double getOverdraft() {
+ return overdraft;
+ }
+}
diff --git a/src/me/teridax/jcash/banking/Owner.java b/src/me/teridax/jcash/banking/Owner.java
new file mode 100644
index 0000000..1f337e8
--- /dev/null
+++ b/src/me/teridax/jcash/banking/Owner.java
@@ -0,0 +1,66 @@
+package me.teridax.jcash.banking;
+
+import java.util.Objects;
+
+@SuppressWarnings("unused")
+public final class Owner {
+ private int uid;
+ private String familyName;
+ private String name;
+ private String street;
+ private int zip;
+ private String city;
+
+ private Owner() { }
+
+ public Owner(int uid, String familyName, String name, int zip, String city, String street) {
+ this.uid = uid;
+ this.familyName = familyName;
+ this.name = name;
+ this.zip = zip;
+ this.city = city;
+ this.street = street;
+ }
+
+ public long getUid() {
+ return uid;
+ }
+
+ public String getFamilyName() {
+ return familyName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getZip() {
+ return zip;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public String getStreet() {
+ return street;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(uid, familyName, name, zip, city, street);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Owner) {
+ return this.uid == ((Owner) obj).getUid();
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("@Owner[uid=%08x, familyName=%s, name=%s, zip=%s, city=%s, street=%s]", uid, familyName, name, zip, city, street);
+ }
+}
diff --git a/src/me/teridax/jcash/banking/SavingsAccount.java b/src/me/teridax/jcash/banking/SavingsAccount.java
new file mode 100644
index 0000000..7e36c58
--- /dev/null
+++ b/src/me/teridax/jcash/banking/SavingsAccount.java
@@ -0,0 +1,16 @@
+package me.teridax.jcash.banking;
+
+@SuppressWarnings("unused")
+public class SavingsAccount extends Account {
+
+ private double interest;
+
+ public SavingsAccount(int iban, int pin, double interest, Owner owner) {
+ super(iban, pin, owner);
+ this.interest = interest;
+ }
+
+ public double getInterest() {
+ return interest;
+ }
+}
diff --git a/src/me/teridax/jcash/decode/Decoder.java b/src/me/teridax/jcash/decode/Decoder.java
new file mode 100644
index 0000000..66542f1
--- /dev/null
+++ b/src/me/teridax/jcash/decode/Decoder.java
@@ -0,0 +1,118 @@
+package me.teridax.jcash.decode;
+
+import org.junit.Test;
+
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class Decoder {
+
+ private static final Locale LOCALE = Locale.GERMANY;
+ private static final NumberFormat LOCAL_NUMBER_FORMAT = NumberFormat.getInstance(LOCALE);
+
+ public static double decodePercent(String number) throws IllegalArgumentException, NullPointerException {
+ Objects.requireNonNull(number);
+
+ // trim the number and cut out optional percent symbols
+ var trimmed = number.trim().replace("%", "");
+
+ try {
+ return LOCAL_NUMBER_FORMAT.parse(trimmed).doubleValue();
+ } catch (ParseException ex) {
+ throw new IllegalArgumentException("Not a valid number: " + number, ex);
+ }
+ }
+
+ public static double decodeCurrency(String currency) throws IllegalArgumentException, NullPointerException {
+ Objects.requireNonNull(currency);
+
+ try {
+ return LOCAL_NUMBER_FORMAT.parse(currency.trim()).doubleValue();
+ } catch (ParseException ex) {
+ throw new IllegalArgumentException("Not a valid currency in german locale: " + currency, ex);
+ }
+ }
+
+ public static int decodeSerialNumber(String number) throws IllegalArgumentException, NullPointerException {
+ Objects.requireNonNull(number);
+
+ // check if the string is a valid unsigned number
+ try {
+ LOCAL_NUMBER_FORMAT.setParseIntegerOnly(true);
+ var serialNumber = LOCAL_NUMBER_FORMAT.parse(number.trim());
+ LOCAL_NUMBER_FORMAT.setParseIntegerOnly(false);
+ return serialNumber.intValue();
+ } catch (ParseException ex) {
+ throw new IllegalArgumentException("Not a valid serial number: " + number, ex);
+ }
+ }
+
+ public static String decodeName(String name) throws IllegalArgumentException, NullPointerException {
+ Objects.requireNonNull(name);
+
+ var trimmed = name.trim();
+
+ // check if the string is a valid unsigned number
+ if (!trimmed.trim().chars().allMatch(Character::isLetter))
+ throw new IllegalArgumentException("Not a valid name: " + name);
+
+ return trimmed;
+ }
+
+ public static String decodeStreet(String street) throws IllegalArgumentException, NullPointerException {
+ Objects.requireNonNull(street);
+
+ var pattern = Pattern.compile("\\S+(\\s+\\d+(/\\d+)?)?", Pattern.CASE_INSENSITIVE);
+ var matcher = pattern.matcher(street);
+ if (matcher.find()) {
+ return matcher.group();
+ } else {
+ throw new IllegalArgumentException("not a void address");
+ }
+ }
+
+ @Test
+ public void testDecodeSuccessfulFunctions() {
+ decodeSerialNumber("95786978625347895");
+ decodeSerialNumber(" 927856347 ");
+ decodeSerialNumber("0");
+
+ decodeName("Adolf");
+ decodeName("Günther");
+ decodeName("Saßkia");
+
+ decodeStreet("Bahnhofstraße 40/1");
+ decodeStreet("Gülleweg 9");
+ decodeStreet("Echsengaße 67 / 4");
+
+ assertEquals(decodePercent("1,4%"), 1.4d);
+ assertEquals(decodePercent("99"), 99.0d);
+ assertEquals(decodePercent("1,003 %"), 1.003d);
+
+ assertEquals(decodeCurrency("1,3€"), 1.3d);
+ assertEquals(decodeCurrency("145,34"), 145,34d);
+ assertEquals(decodeCurrency("0,45 €"), 0.45d);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testDecodeInvalidFunctions() {
+ decodeSerialNumber("q0948tvb6q047t 740 t74z0tz 784");
+ decodeSerialNumber("-39867.8475");
+ decodeSerialNumber("-398678475");
+ decodeSerialNumber(" ß9qu908t76q34798t6q734vb9843");
+
+ decodeName("John Doe");
+ decodeName("3490qt67v 0b34");
+ decodeName("Alexander9");
+ decodeName("-ga76re78g6$§");
+
+ decodeStreet("Bahnhofstraße -40/1");
+ decodeStreet("Gülleweg 9//567");
+ decodeStreet("23Echsengaße 67 / 4 Hofwetg 9");
+ }
+}