diff --git a/R/HelperFunctions.R b/R/HelperFunctions.R
new file mode 100644
index 0000000000000000000000000000000000000000..3ab8c70e9b2c1416053c5262f2f3aa7a2e372edc
--- /dev/null
+++ b/R/HelperFunctions.R
@@ -0,0 +1,40 @@
+calculatePVSurvival = function(q, advance, arrears, v=1) {
+  # assuming advance and arrears have the same dimensions...
+  init = advance[1]*0;
+  l = max(length(q), length(advance), length(arrears));
+  q = pad0(q, l, value=1);
+  advance = pad0(advance, l, value=init);
+  arrears = pad0(arrears, l, value=init);
+
+  # TODO: Make this work for matrices (i.e. currnently advance and arrears are assumed to be one-dimensional vectors)
+  # TODO: Replace loop by better way (using Reduce?)
+  res = rep(0, l+1);
+  for (i in l:1) {
+    res[i] = advance[i] + v*(1-q[i])*(arrears[i] + res[i+1]);
+  }
+  res
+}
+
+calculatePVDeath = function(q, benefits, v=1) {
+  init = benefits[1]*0;
+  l = max(length(q), length(benefits));
+  q = pad0(q, l, value=1);
+  benefits = pad0(benefits, l, value=init);
+
+  # TODO: Make this work for matrices (i.e. currently benefits are assumed to be one-dimensional vectors)
+  # TODO: Replace loop by better way (using Reduce?)
+  res = rep(init, l+1);
+  for (i in l:1) {
+    res[i] = v*q[i]*benefits[i] + v*(1-q[i])*res[i+1];
+  }
+  res
+}
+
+pad0 = function(v, l, value=0) {
+  if (l>=length(v)) {
+    c(v, rep(value, l-length(v)))
+  } else {
+    v[0:l]
+  }
+}
+
diff --git a/R/InsuranceTarif.R b/R/InsuranceTarif.R
index 7f2c77b03bf366d2e035a51b19455386cfcff0c4..30e0970cdf78caae95f34c445b6ce9223c1242ff 100644
--- a/R/InsuranceTarif.R
+++ b/R/InsuranceTarif.R
@@ -1,53 +1,264 @@
 library(R6);
-library("lifecontingencies")
+library(lifecontingencies)
+library(objectProperties)
+library(foreach)
 
+TariffTypeEnum = setSingleEnum("TariffType", levels = c("annuity", "wholelife", "endowment", "pureendowment"))
+PaymentTimeEnum = setSingleEnum("PaymentTime", levels = c("in advance", "in arrears"))
+#PaymentCountEnum = setSingleEnum(PaymentCount, levels = c(1,2,3))
 
-# base class for Insurance Tarifs (holding contrat-independent values and 
+
+# Initialize a cost matrix with dimensions: [CostType, Basis, Period], with:
+#     CostType: alpha, Zillmer, beta, gamma
+#     Basis:    SumInsured, SumPremiums, GrossPremium
+#     Period:   once, premiumPeriod, policyPeriod
+initializeCosts = function() {
+  array(0,
+        dim=list(5, 3, 3),
+        dimnames=list(
+          c("alpha", "Zillmer", "beta", "gamma", "gamma_nopremiums"),
+          c("SumInsured", "SumPremiums", "GrossPremium"),
+          c("once", "PremiumPeriod", "PolicyPeriod")
+        )
+      )
+}
+
+calculatePVSurvival = function(q, advance, arrears, v=1) {
+  # assuming advance and arrears have the same dimensions...
+  init = advance[1]*0;
+  l = max(length(q), length(advance), length(arrears));
+  q = pad0(q, l, value=1);
+  advance = pad0(advance, l, value=init);
+  arrears = pad0(arrears, l, value=init);
+
+  # TODO: Make this work for matrices (i.e. currnently advance and arrears are assumed to be one-dimensional vectors)
+  # TODO: Replace loop by better way (using Reduce?)
+  res = rep(0, l+1);
+  for (i in l:1) {
+    res[i] = advance[i] + v*(1-q[i])*(arrears[i] + res[i+1]);
+  }
+  res
+}
+
+# base class for Insurance Tarifs (holding contrat-independent values and
 # providing methods to calculate cash flows, premiums, etc.). Objects of this
-# class do NOT contain contract-specific values like age, death probabilities, 
+# class do NOT contain contract-specific values like age, death probabilities,
 # premiums, reserves, etc.
 InsuranceTarif = R6Class(
-  "InsuranceTarif", 
+  "InsuranceTarif",
   public  = list(
     name  = "Insurance Contract Type",
     tarif = "Generic Tarif",
     desc  = "Description of the contract",
-    
-    states = c("Lebend", "Tot"),
+
+    states = c("alive", "dead"),
     mortalityTable = NA,
-    interest=0,
+    i = 0, # guaranteed interest rate
+    v = 1, # discount factor
+    tariffType = TariffTypeEnum("wholelife"), # possible values: annuity, wholelife, endowment, pureendowment
+    widowFactor = 0,
+
+    premiumRefund = 0,
+    premiumRefundSpread = 0,
+
+    advanceBonus = 0,
+    sumRebate = 0,
+
+    costs = list(),
+    paymentsPerYearSurcharge = list("1" = 0.0, "2" = 0.01, "4" = 0.015, "12" = 0.02),
+    surcharges = list("tax" = 0.04, "unitcosts" = 0, "security" = 0, "noMedicalExam" = 0),
 
-    initialize = function (name=NA, mortalityTable=NA, interest=NA,...) {
+
+    initialize = function(name = NA, mortalityTable = NA, i = NA, type = "wholelife", ..., costs) {
       if (!missing(name))           self$name = name;
       if (!missing(mortalityTable)) self$mortalityTable = mortalityTable;
-      if (!missing(interest))       self$interest = interest;
-      cat(paste0("Initializing Insurance Tarif ", self$name, "...\n"))
+      if (!missing(i))              self$i = i;
+      if (!missing(type))           self$tariffType = type;
+      self$costs = if (!missing(costs)) costs else initializeCosts();
+
+      self$v = 1/(1+self$i);
+
+      cat(paste0("Initializing Insurance Tarif ", self$name, "...\n"));
     },
-    getTransitionProbabilities = function (age, ..., YOB=2000) {
-      ages = ages(self$mortalityTable, YOB=YOB);
-      q = deathProbabilities(self$mortalityTable, YOB=YOB);
-      if (age>0) {
+    getAges = function(age, ..., YOB = 2000) {
+      ages = ages(self$mortalityTable, YOB = YOB);
+      if (age > 0) {
         ages = ages[-age:-1];
+      }
+      ages
+    },
+    getTransitionProbabilities = function(age, ..., YOB = 2000) {
+      ages = self$getAges(age, YOB = YOB);
+      q = deathProbabilities(self$mortalityTable, YOB = YOB);
+      if (age > 0) {
         q    = q[-age:-1];
       }
-      p = 1-q;
-      len = length(p);
-      df=data.frame(p, q, rep(0,len), rep(1,len), row.names=ages)
+      # p = 1 - q;
+      # len = length(p);
+      # df = data.frame(p, q=q, rep(0,len), rep(1,len), row.names = ages)
+      df = data.frame(age=ages, q=q, row.names = ages-age)
       df
     },
-    getCashFlowsState = function (age, ..., policyPeriod=inf, deferral=0, maxAge=150) {
-      cf = list()
-      # TODO
+    getBasicCashFlows = function(age, ..., guaranteed = 0, policyPeriod = inf, deferral = 0, maxAge = getOmega(self$mortalityTable)) {
+      maxlen = min(maxAge - age, policyPeriod);
+
+      cf = list(
+        guaranteed = rep(0, maxAge - age),
+        survival = rep(0, maxAge - age),
+        death = rep(0, maxAge - age)
+      );
+      if (self$tariffType == "annuity") {
+        # guaranteed payments exist only with annuities (first n years of the payment)
+        cf$guaranteed = c(rep(0, deferral), rep(1, guaranteed), rep(0, max(0, maxAge - age - deferral - guaranteed)))
+        cf$survival = c(rep(0, deferral + guaranteed), rep(1, max(0, maxlen - deferral - guaranteed)), rep(0, maxAge - age - maxlen))
+      } else {
+        if (self$tariffType == "endowment" || self$tariffType == "pureendowment") {
+          cf$survival = c(rep(0, policyPeriod), 1, rep(0, maxAge - age - maxlen - 1));
+        }
+        if (self$tariffType == "endowment" || self$tariffType == "wholelife") {
+          cf$death = c(rep(0, deferral), rep(1, maxlen - deferral), rep(0, maxAge - age - maxlen));
+        }
+      }
+      cf
     },
-    getCashFlowsTransition = function (age, ..., policyPeriod=inf, deferral=0, maxAge=150) {
-      # TODO
-    }
+
+    getCashFlows = function(age, ..., premiumPayments = "in advance", benefitPayments = "in advance", guaranteed = 0, policyPeriod=Inf, premiumPaymentPeriod = policyPeriod, deferral=0, maxAge = getOmega(self$mortalityTable), basicCashFlows = NA) {
+      ages = self$getAges(age, YOB = YOB);
+      cflen = maxAge - age + 1;
+      if (missing(basicCashFlows)) {
+        basicCashFlows = self$getBasicCashFlows(age = age, ..., guaranteed = guaranteed,
+              policyPeriod = policyPeriod, deferral = deferral, maxAge = maxAge);
+      }
+      zeroes = pad0(0, cflen);
+      cf = data.frame(
+        premiums_advance = zeroes,
+        premiums_arrears = zeroes,
+        guaranteed_advance = zeroes,
+        guaranteed_arrears = zeroes,
+        survival_advance = zeroes,
+        survival_arrears = zeroes,
+        death_SumInsured = zeroes,
+        death_GrossPremium = zeroes,
+        death_PremiumFree = zeroes,
+        row.names = ages-age
+      );
+
+      # Premiums:
+      premiums = pad0(rep(1, min(premiumPaymentPeriod, policyPeriod)), cflen);
+      if (premiumPayments == "in advance") {
+        cf$premiums_advance = premiums;
+      } else {
+        cf$premiums_arrears = premiums;
+      }
+
+      # Survival Benefits
+      if (benefitPayments == "in advance") {
+        cf$guaranteed_advance = pad0(basicCashFlows$guaranteed, cflen);
+        cf$survival_advance = pad0(basicCashFlows$survival, cflen);
+      } else {
+        cf$guaranteed_arrears = pad0(basicCashFlows$guaranteed, cflen);
+        cf$survival_arrears = pad0(basicCashFlows$survival, cflen);
+      }
+
+      # Death Benefits
+      cf$death_SumInsured = pad0(basicCashFlows$death, cflen);
+      cf$death_PremiumFree = cf$death_SumInsured;
+      # premium refund
+      if (self$premiumRefund != 0) {
+        totalpremiumcf = cf$premiums_advance + pad0(c(0, cf$premiums_arrears), cflen);
+
+        # death benefit for premium refund is the sum of all premiums so far:
+        cf$death_GrossPremium = pad0(Reduce("+", totalpremiumcf[0:policyPeriod], accumulate=TRUE), cflen)
+      }
+
+      cf
+    },
+
+    getCashFlowsCosts = function(age, ..., policyPeriod=Inf, premiumPaymentPeriod = policyPeriod, maxAge = getOmega(self$mortalityTable)) {
+      cflen = maxAge - age + 1;
+      policyPeriod = min(maxAge - age, policyPeriod);
+      premiumPeriod = min(policyPeriod, premiumPaymentPeriod);
+
+      dm = dim(self$costs);
+      dmnames = dimnames(self$costs);
+      cf = array(0, dim=list(cflen, dm[1], dm[2]), dimnames=list(0:(cflen-1), dmnames[[1]], dmnames[[2]]));
+      cf[1,,] = cf[1,,] + self$costs[,,"once"]
+      for(i in 1:premiumPeriod) {
+        cf[i,,] = cf[i,,] + self$costs[,,"PremiumPeriod"];
+      }
+      for(i in 1:policyPeriod) {
+        cf[i,,] = cf[i,,] + self$costs[,,"PolicyPeriod"];
+      }
+      cf
+    },
+
+    presentValueCashFlows = function(cashflows, age, ..., maxAge = getOmega(self$mortalityTable)) {
+      q = self$getTransitionProbabilities (age, ...);
+      ages = self$getAges(age, YOB = YOB);
+      pv = data.frame(
+        age = c(q$age, max(q$age)+1),
+        premiums = calculatePVSurvival (q$q, cashflows$premiums_advance, cashflows$premiums_arrears, v=self$v),
+        guaranteed = calculatePVSurvival (q$q*0, cashflows$guaranteed_advance, cashflows$guaranteed_arrears, v=self$v),
+        survival = calculatePVSurvival (q$q, cashflows$survival_advance, cashflows$survival_arrears, v=self$v),
+        death_SumInsured = calculatePVDeath (q$q, cashflows$death_SumInsured, v=self$v),
+        death_GrossPremium = calculatePVDeath (q$q, cashflows$death_GrossPremium, v=self$v),
+        death_PremiumFree = calculatePVDeath (q$q, cashflows$death_PremiumFree, v=self$v),
+
+        row.names = c(rownames(q), maxAge-age+1)
+      );
+      pv
+    },
+
+
+    # Dummy to allow commas
+    dummy = 0
   )
 );
 
-TestTarif = InsuranceTarif$new(name="Testtarif", mortalityTable=AVOe2005R.male)
+costs = initializeCosts();
+# costs["alpha", "SumInsured",] = c(1,2,5);
+# costs["beta", "SumPremiums",] = c(3,2,1);
+costs["alpha", "SumPremiums", "once"] = 0.05;
+costs["Zillmer", "SumPremiums", "once"] = 0.04;
+costs["gamma", "SumInsured", "PolicyPeriod"] = 0.005;
+costs["gamma_nopremiums", "SumInsured", "PolicyPeriod"] = 0.01;
+
+costs
+
+TestTarif = InsuranceTarif$new(name = "Testtarif", mortalityTable = AVOe2005R.male, type = "annuity", costs=costs)
 str(TestTarif)
-TestTarif$getTransitionProbabilities(YOB=1980, age=30)
+TestTarif$costs
+q = TestTarif$getTransitionProbabilities(YOB = 1980, age = 30)
+TestTarif = InsuranceTarif$new(name = "Testtarif", mortalityTable = AVOe2005R.male, type = "wholelife", costs=costs)
+TestTarif$getBasicCashFlows(YOB = 1980, age = 30, policyPeriod = 5, deferral = 3, guaranteed=10)
+
+# Gemischte Versicherung, i=1%, AVÖ2005R Unisex, YOB=1980, age=30, Laufzeit=10, Prämienzahlungsdauer=5,
+TestTarif = InsuranceTarif$new(name = "Testtarif", mortalityTable = AVOe2005R.unisex, type = "endowment", costs=costs, i=0.01)
+TestTarif$getBasicCashFlows(YOB = 1980, age = 30, premiumPaymentPeriod = 5, policyPeriod = 10, deferral = 0, guaranteed=0)
+
+TestTarif$costs=costs;
+TestTarif$premiumRefund = 0;
+
+
+cf = TestTarif$getCashFlows(YOB = 1980, age = 30, premiumPaymentPeriod = 5, policyPeriod = 10, deferral = 0, guaranteed=0); cf
+cfc = TestTarif$getCashFlowsCosts(YOB = 1980, age = 30, premiumPaymentPeriod = 5, policyPeriod = 10, deferral = 0, guaranteed=0); cfc
+
+pv = TestTarif$presentValueCashFlows(cf, age = 30, YOB=1980); pv
+pvc = TestTarif$presentValueCashFlowsCosts(cfc, age=30, YOB=1980); pv
+
+cf
+cf[,1]
+
+
+str(cf$premiums_advance)
+calculatePVSurvival(q$q, cf$premiums_advance, cf$premiums_arrears, v=1/1.01)
+calculatePVSurvival(q$q, cf$survival_advance, cf$survival_arrears, v=1/1.01)
+
+calculatePVDeath(q$q, cf$death_SumInsured, v=1/1.01)
+calculatePVDeath(q$q, cf$death_GrossPremium, v=1/1.01)
+calculatePVDeath(q$q, cf$death_PremiumFree, v=1/1.01)
+
+cf
 
 
 InsuranceContract = R6Class(
@@ -56,16 +267,24 @@ InsuranceContract = R6Class(
     tarif = NA,
     YOB = NA,
     age = NA,
-    policyPeriod = inf,
+    policyPeriod = Inf,
+    premiumPaymentPeriod = 1,
     deferral = 0,
-    
+    guaranteed = 0,
+
+    premiumPayments = PaymentTimeEnum("in advance"),
+    benefitPayments = PaymentTimeEnum("in advance"),
+
+    premiumPaymentsPerYear = 1,
+    benefitPaymentsPerYear = 1, # Only for annuities!
+
+
     transitionProbabilities = NA,
-    cashFlowsState = NA,
-    cashFlowsTransition = NA,
+    cashFlows = NA,
     #    cashFlowsState = list(c(0), c(0)),
     #    cashFlowsTransition = list(matrix(c(0,1,0,1), 2, 2, byrow=TRUE)),
-    
-    initialize = function (tarif, age, policyPeriod=inf, ..., deferral=0, YOB=1975) {
+
+    initialize = function(tarif, age, policyPeriod = inf, ..., deferral = 0, YOB = 1975) {
       if (!missing(tarif)) self$tarif = tarif;
       if (!missing(age)) self$age = age;
       if (!missing(YOB)) self$YOB = YOB;
@@ -74,18 +293,18 @@ InsuranceContract = R6Class(
       self$determineTransitionProbabilities();
       self$determineCashFlows();
     },
-    
+
     determineTransitionProbabilities = function() {
       self$transitionProbabilities = self$tarif$getTransitionProbabilities(self$age, self$YOB);
     },
-    
+
     determineCashFlows = function() {
-      self$cashFlowsState = self$tarif$getCashFlowsState(age=self$age, YOB=self$YOB, policyPeriod=self$policyPeriod, deferral=self$deferral, maxAge=self$age+length(self$transitionProbabilities));
-      self$cashFlowsTransition = self$tarif$getCashFlowsState(age=self$age, YOB=self$YOB, policyPeriod=self$policyPeriod, deferral=self$deferral, maxAge=self$age+length(self$transitionProbabilities));
-      
+      self$cashFlowsState = self$tarif$getCashFlowsState(age = self$age, YOB = self$YOB, policyPeriod = self$policyPeriod, deferral = self$deferral, maxAge = self$age + length(self$transitionProbabilities));
+      self$cashFlowsTransition = self$tarif$getCashFlowsState(age = self$age, YOB = self$YOB, policyPeriod = self$policyPeriod, deferral = self$deferral, maxAge = self$age + length(self$transitionProbabilities));
+
     }
-    
-    
+
+
 
 
   )
@@ -145,11 +364,11 @@ df
 # createCostStructure=function(age=35,contractLength=inf,
 #   alphaVS,
 #   alphaBP,
-#   
-# 
+#
+#
 # CostStructure=setClass(
 #   "CostStructure",
-#   
+#
 # )
 
 
@@ -172,8 +391,8 @@ setMethod("calculate", "InsuranceContract",
             # 0a: Unterjährigkeit
             m = object@unterjährigkeit;
             object@cache.uj=calcUnterjährigkeit(m=m, i=object@interest, order=object@unterjährigkeitsapproximation);
-            
-            
+
+
             # 1) Generate mortality table
             if (!is.null(object@contractLength) && is.finite(object@contractLength)) {
               ages = (object@age):(object@contractLength);
@@ -190,27 +409,27 @@ setMethod("calculate", "InsuranceContract",
               pxyn = pxn * pxn2;
               object@probabilities = data.frame(object@probabilities, ages2=ages2, q2=qx2, pxn2=pxn2, pxyn=pxyn);
             }
-            
-            
+
+
             # 2) Properly set up the payment and cost cash flow data frames
-            
+
             # 3) Calculate all NPVs of the payment and the cost cash flows (recursively)
             # 3a: life-long annuities for person 2 (and person 1+2), in case the death benefit is a life-long widow's annuity
-            
+
             # 4) Set up the coefficients of the NPVs for the premium calculation
-            
+
             # 5) Calculate the gross premium
             # 6) Calculate the net premium and the Zillmer premium
-            
+
             # 7) Calculate all reserves (benefits and costs)
-            
+
             # 8) Calculate Spar- und Risikoprämie from the net premium and the reserves
-            
+
             # 9) Calculate VS after Prämienfreistellung
             # 9a: Calculate all reserves after Prämienfreistellung
-            
+
             # 10) Calculate the Bilanz reserves
-            
+
             # 11) Calculate the Rückkaufswert
             #   max(object@ages,na.rm=TRUE);
             object
@@ -225,9 +444,9 @@ beispielvertrag = InsuranceContract(
   #     contractLength=30,
   mortalityTable=AVOe2005R.unisex, mortalityTable2=AVOe2005R.unisex,
   interest=0.0125,
-  
+
   unterjährigkeit=12, unterjährigkeitsapproximation=1.5,
-  
+
   #     deathPayments=list(),
   #     survivalPayments=list(),
   #     costCashflows=data.frame(),
@@ -235,4 +454,4 @@ beispielvertrag = InsuranceContract(
 );
 beispielvertrag=calculate(beispielvertrag)
 beispielvertrag
-# data.frame(x=0:121, qx=deathProbabilities(AVOe2005R.unisex, YOB=1948))
\ No newline at end of file
+# data.frame(x=0:121, qx=deathProbabilities(AVOe2005R.unisex, YOB=1948))
diff --git a/ValuationTables.Rproj b/ValuationTables.Rproj
index 96bdc3da74e6898e53b6b1412e5c6660588c7a69..d603dfcc0ff2ec2ee017a886dc6d12974bb4fe17 100644
--- a/ValuationTables.Rproj
+++ b/ValuationTables.Rproj
@@ -12,5 +12,8 @@ Encoding: UTF-8
 RnwWeave: Sweave
 LaTeX: pdfLaTeX
 
+AutoAppendNewline: Yes
+StripTrailingWhitespace: Yes
+
 BuildType: Package
 PackageInstallArgs: --no-multiarch