/*
 * Minimal BankAccount class in C, version 2.
 * CSE 374 demo, 12/07-12/15, HP
 *
 * This file contains both declarations and implementations for the 
 * BankAccount class.
 *
 * Abstraction: An object consists of both data and (pointers to) function 
 * members as before.  But this time, the function pointers are not duplicated
 * in each object.  Instead there is a single "vtable" of function pointers 
 * for the class BAccount, and each object begins with a pointer to this 
 * vtable.  Calls to member functions are indirect through this table.
 */

#include <stdio.h>
#include <stdlib.h>

/* type definitions for BAccount class and vtable */

typedef struct bank_account        BAccount;
typedef struct bank_account_vtable BAcccount_vtable;

/* Virtual function table layout for BAccount class */

struct bank_account_vtable {
  /* "public" function pointers for Class BAccount. */
  /* All contain a "this" first parameter */
  int (*get_account)(BAccount*);
  int (*get_balance)(BAccount*);
  void (*deposit)(BAccount*, int);
};

/* BAccount object layout */

struct bank_account {
  /* vtable pointer */
  BAcccount_vtable *vtbl;
	
  /* "private" data members */
  int number;	  /* account number */
  int balance;	  /* account balance */
};


/* BAccount implementation */

/* member function prototypes */
int  BAccount_get_account(BAccount*);
int  BAccount_get_balance(BAccount*);
void BAccount_deposit(BAccount*, int);

/* BAccount vtable (static; initialized at startup w/function pointers) */
static BAcccount_vtable BAccount_vtbl = 
  { &BAccount_get_account, &BAccount_get_balance, &BAccount_deposit };


/* Combination "new" and "constructor" method for BAccount objects */
/* Return a new BAccount object with given account number and initial */
/* balance */
BAccount * new_BAccount(int number, int balance) {
  /* allocate object */
  BAccount * this = (BAccount *)malloc(sizeof(BAccount));
	
  /* initialize vtable pointer */
  this->vtbl = &BAccount_vtbl;
	
  /* initialize data */
  this->number  = number;
  this->balance = balance;
	
  /* return reference to newly allocated and initialized object */
  return this;
}
	
/* Member functions (methods) */
/* Note that all contain a pointer to the receiver object they are  */
/* associated with.  We need to do this explicitly in C; it is done */
/* implicitly in C++, Java, etc. */

int BAccount_get_account(BAccount *this) { return this->number;  }

int BAccount_get_balance(BAccount *this) { return this->balance; }

void BAccount_deposit(BAccount *this, int amount) {
  this->balance += amount;
}

/* test program */
/* Notice explicit "this" parameters to member functions.    */
/* In C++ these parameters are generated by the C++ compiler */
/* automatically behind the scenes. */
/* This time methods are called indirectly through the object vtable. */
/* This indirect call would be done automatically by a C++ compiler.  */
int main() {
  BAccount *one = new_BAccount(17,0);
  //one->deposit(one,100);
  one->vtbl->deposit(one,100);
  printf("balance is %d\n", one->vtbl->get_balance(one));
	
  BAccount *two = new_BAccount(42,500);
  printf("balance is %d\n", two->vtbl->get_balance(two));
	
  free(one);
  free(two);
  return 0;
}