/******************************************************
 * MT285 TMA03 q4a.cpp
 * for Q4 (a), (b) and (c)
 * IDD Billing report program
 * associated files: customer.txt, rate.txt, log.txt
 * programming by Allen Lam (99043953)
 * compiled by bcb, for DOS only
 * Mar 2001
 ******************************************************/

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

/**********************************************
  Miscellaneous function for presentation purposes
*/

void dashline(){
  int i;
  for (i=0; i<80; i++) printf("=");
}

void headline(){
  clrscr(); printf("IDD phone bill daily report\n");
  dashline();
}

void moreline(){
  gotoxy(1,24); dashline();
  printf("Press any key to continue...");
  getch();
}

void quitline(){
  gotoxy(1,24); dashline();
  printf("End of report. Press any key to quit...");
  getch();
}

/**********************************************
    Rate Table ADT
*/

/* Size of the Table Array */
#define RT_SIZE 16

struct RT_RateCell {
    int rateType;
    float rate;    /* dollar per MINUTE */
};
struct RT_RateCell RT_rateTable[RT_SIZE];

int RT_count;    /* number of rate types loaded from the file */

/**********************************************
    This function initialize the rateTable array by
    setting its counter (RT_count) and loading the data
    from the rate data file (rate.txt).
*/
void RT_initialize()    {
    FILE* fp;
    RT_count = 0;
    /* opening the file for reading and error checking */
    if ((fp = fopen("rate.txt.", "r")) == NULL) {
        fprintf(stderr, "Error in reading rate.txt.\n");
        fprintf(stderr, "Please make sure the file is in the local directory.\n");
        exit(1);
    }
    /* reading the rate file by each pair of data*/
    while (fscanf(fp, "%d %f",  &(RT_rateTable[RT_count].rateType),
        &(RT_rateTable[RT_count].rate)) != EOF) {
        RT_count++;
        if (RT_count >= RT_SIZE)
            break;
    }
    fclose(fp);    /* close the file for cleanliness */
}

/**********************************************
    This function returns the rate of a given rateType.
    If the rateType does not exist in the table, it returns 0.
*/
float RT_getRate(int rateType)  {
    /* it loops through the array one by one and look for
    a record with the desired rateType. */
    for (int i=0; i<RT_count; i++)   {
        if (RT_rateTable[i].rateType == rateType)
            return RT_rateTable[i].rate;
    }
    return 0;
}

/**********************************************
    This function calculates the cost of a call,
    given the rateType, and duration in seconds

    Requirement of Q4a is implemented here
    ======================================
*/
float RT_calculateCallCost(int rateType, int duration) {
    float rate, total;
    rate = RT_getRate(rateType);
    if (duration<=6) duration = 0;                            /* failed call */
    else if (duration<60) duration = 60;                      /* round up */
    else if (duration%60<=20 && duration%60>0)
      duration -= duration%60;                                /* round down */
    else if (duration%60>20) duration += (60 - duration%60);  /* round up */
    total = rate * (float)duration / 60;
    if (total>0.0) total += 0.2;
    return total;
}

/**********************************************
    This function prints the rate schedule nicely as
    a table.
*/
void RT_printRates()    {
    headline();
    printf("RateType   Rate($)\n");
    printf("--------------------\n");
    for (int i=0; i<RT_count; i++)   {
        printf("%5.d %10.2f\n", RT_rateTable[i].rateType,
            RT_rateTable[i].rate);
    }
}

/***************************************************************************/

/**********************************************
    Customer Table ADT
*/

#define ID_MAXLENGTH 8
#define NAME_MAXLENGTH 64

/* forward declaration (so it can be used as a field in the following decl */
struct CT_CustomerCell;
/* a customer record */
struct CT_CustomerCell {
    char customerID[ID_MAXLENGTH]; /* id of this customer record */
    char name[NAME_MAXLENGTH];     /* name of this customer record */
    struct CT_CustomerCell* next;  /* pointing to the next node in the linked-list */
};

struct CT_CustomerCell* CT_head;  /* pointing to the first node in the linked-list */

/**********************************************
  Question 4(b) Customer Table ADT function
  =========================================
  Initialize the ADT.
  Open and read file customer.txt. Built a linked-list of CT_CustomerCell.
*/
void CT_initialize(){
  FILE* fp;
  CT_CustomerCell* p;
  CT_CustomerCell* tail;

  if ((fp = fopen("customer.txt", "r"))==NULL){
    puts("Error in opening file CUSTOMER.TXT"); exit(1);
  }
  if ((tail = CT_head =
    (CT_CustomerCell*)malloc(sizeof(CT_CustomerCell)))==NULL){
    puts("Error in initializing customer table."); exit(1);
  }
  while (!feof(fp)){
    if ((p = (CT_CustomerCell*)malloc(sizeof(CT_CustomerCell)))==NULL){
      puts("Error in initializing customer table."); exit(1);
    }
    fscanf(fp, "%s %s", p->customerID, p->name);
    p->next = NULL;
    tail->next = p;
    tail = p;
  }
  fclose(fp);
  free(p); free(tail);
}

/**********************************************
  Question 4(b) Customer Table ADT function
  =========================================
  Determine if the customerID exists in the table. Return True or False
*/
int CT_existCustomer(char* customerID) {
  CT_CustomerCell* p;              /* linked-list pointer */

  p = CT_head;
  while (p->next!=NULL){
    p = p->next;
    if (!strcmp(p->customerID, customerID)) return 1;
  }
  return 0;
}

/**********************************************
  Question 4(b) Customer Table ADT function
  =========================================
  Returns the name of the customer with customerID.
  Returns NULL if customerID not exists.
*/
char* CT_getName(char* customerID) {
  CT_CustomerCell* p;              /* linked-list pointer */

  p = CT_head;
  while (p->next!=NULL){
    p = p->next;
    if (!strcmp(p->customerID, customerID)) return p->name;
  }
  return NULL;
}

/**********************************************
  Question 4(c)
  =============
  Read data from log.txt, compute the daily spending of each customer,
  printout a summary list showing ID, name and $.
*/

  /* an ADT for customer spending summary */
  typedef struct CUST{
    char id[ID_MAXLENGTH];      /* ID of customer */
    char name[NAME_MAXLENGTH];  /* name of customer */
    float amount;               /* daily spending */
    struct CUST* next;          /* pointer to next item in linked-list */
  } cust;

  cust* head;                   /* head of linked-list */
  cust* tail;                   /* tail of linked-list */
  cust* p;                      /* a sharable temporary pointer */

/* initialize cust linked-list */
void initSummary(){
  tail = head = (cust*)malloc(sizeof(cust));
  head->next = NULL;
}

/* determine if id already exist in linked-list,
   return pointer of id if found; return NULL if not found */
cust* idSearch(char* id){
  p = head;
  while (p->next!=NULL){
    p = p->next;
    if (!strcmp(id, p->id)) return p;
  }
  return NULL;
}

/* if id exist in linked-list, add amount to it,
   else add new item in linked-list */
void addSummaryItem(char* id, char* name, float amount){
  if (idSearch(id)==NULL){
    if ((p = (cust*)malloc(sizeof(cust)))==NULL){
      puts("Insufficient memory!"); exit(1);
    }
    strcpy(p->id, id); strcpy(p->name, name); p->amount = amount;
    p->next = NULL;
    tail->next = p;
    tail = p;
  }
  else p->amount += amount;
}

void displaySummary(){
  p = head;
  while (p->next!=NULL){
    p = p->next;
    printf("   %s          %s%10.2f\n", p->id, p->name, p->amount);
    /* new page */
    if (wherey()>=24){
      moreline(); headline();
    }
  }
  quitline();
}

/* lengthen str to length of len, return str */
char* lengthen(char* str, int len){
  int i;
  int extra;         /* number of extra spaces need to append */
  char blank[NAME_MAXLENGTH];               /* a blank string */

  extra = len - strlen(str);
  for (i=0; i<extra; i++) blank[i] = ' ';
  blank[extra] = '\0';
  strcat(str, blank);
  return str;
}

/* main function of Q4c, process log.txt and print summary */
void LogProcessor() {
  FILE* fp;
  char time[5];                 /* time making the call (not used) */
  char id[ID_MAXLENGTH];        /* customer ID */
  int rateType;                 /* rate type of call */
  int duration;                 /* duration of call in second */
  float amount;                 /* $ spent in a call */
  char name[NAME_MAXLENGTH];    /* local copy of customer name */

  if ((fp = fopen("log.txt", "r"))==NULL){
    puts("Error in opening log.txt"); return;
  }
  initSummary();
  puts("");
  puts("Customer ID      Name            Daily Spending($)");
  puts("===========      ====            =================");
  while (!feof(fp)) {
    fscanf(fp, "%s %s %d %d", time, id, &rateType, &duration);
    amount = RT_calculateCallCost(rateType, duration);
    if (amount>0 && CT_existCustomer(id)){
      strcpy(name, CT_getName(id));
      lengthen(name, 16);
      addSummaryItem(id, name, amount);
    }
  }
  fclose(fp);
  displaySummary();
}

/* Main Program. */
void main() {
    RT_initialize();
    RT_printRates();
    CT_initialize();
    LogProcessor();
}


back