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

Demonstration code from 'Professional Linux Programming'

Written by Neil Matthew, Rick Stones et. al.

Copyright (C) 2000 Wrox Press.

http://www.wrox.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

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

/*
  DVD Store Application

  Generic implementation interface

  Insert appropriate calls to underlying implementation

*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <time.h>

#include "dvd.h"

#include "sqlca.h"
#include "dvd_pg.h"


static void trim_member(dvd_store_member *a_member);
static void trim_title(dvd_title *a_title);


int dvd_open_db_login(const char *user, const char *password) {
  return pg_open_db(user, password);
} /* dvd_open_db */

int dvd_open_db(void) {
  return pg_open_db(NULL, NULL);
} /* dvd_open_db */

int dvd_close_db(void) {
  pg_close_db();
  return DVD_SUCCESS;
} /* dvd_close_db */


int dvd_member_set(const dvd_store_member *member_record_to_update) {

  int res;

  if (!pg_check_db_is_connected("dvd_member_set")) return DVD_ERR_NO_FILE;
  if(member_record_to_update == NULL) return DVD_ERR_NULL_POINTER;

  res = pg_member_set(member_record_to_update);
  return res;

} /* dvd_member_set */

int dvd_member_get(const int member_id, dvd_store_member *member_record_to_complete) {
  int res;

  if (!pg_check_db_is_connected("dvd_member_get")) return DVD_ERR_NO_FILE;
  if(member_record_to_complete == NULL) return DVD_ERR_NULL_POINTER;
  
  res = pg_member_get(member_id, member_record_to_complete);
  trim_member(member_record_to_complete); 
  return res;

} /* dvd_member_get */

int dvd_member_create(dvd_store_member *member_record_to_add, int *member_id) {
  int result;

  if (!pg_check_db_is_connected("dvd_member_create")) return DVD_ERR_NO_FILE;
  if(member_record_to_add == NULL || member_id == NULL) return DVD_ERR_NULL_POINTER;
  result = pg_member_insert(member_record_to_add);

  if (result == DVD_SUCCESS) {
    *member_id = member_record_to_add->member_id;
  }
  return result;

} /* dvd_member_create */

int dvd_member_delete(const int member_id) {
  if (!pg_check_db_is_connected("dvd_member_delete")) return DVD_ERR_NO_FILE;

  (void)pg_reserve_title_cancel(member_id);
  (void)pg_disk_rental_cancel_by_member(member_id);
  return pg_member_delete(member_id);
} /* dvd_member_delete */


int dvd_member_search(const char *lname, int *result_ids[], int *count) {

  if (!pg_check_db_is_connected("dvd_member_search")) return DVD_ERR_NO_FILE;

  if(lname == NULL || count == NULL) return DVD_ERR_NULL_POINTER;
  return pg_member_search(lname, result_ids, count);
} /* dvd_member_search */

int dvd_member_get_id_from_number(const char *member_no, int *member_id) {

  if (!pg_check_db_is_connected("dvd_member_get_id_from_number")) return DVD_ERR_NO_FILE;

  if (member_no == NULL || member_id == NULL) return DVD_ERR_NULL_POINTER;
  return pg_member_get_id_from_number(member_no, member_id);
} /* dvd_member_get_id_from_number */

int dvd_title_set(const dvd_title *title_record_to_update) {

  int res;

  if (!pg_check_db_is_connected("dvd_title_set")) return DVD_ERR_NO_FILE;

  if(title_record_to_update == NULL) return DVD_ERR_NULL_POINTER;

  res = pg_title_set(title_record_to_update);
  return res;

} /* dvd_title_set */

int dvd_title_get(const int title_id, dvd_title *title_record_to_complete) {

  int res;

  if (!pg_check_db_is_connected("dvd_title_get")) return DVD_ERR_NO_FILE;

  if(title_record_to_complete == NULL) return DVD_ERR_NULL_POINTER;
  
  res = pg_title_get(title_id, title_record_to_complete);
  trim_title(title_record_to_complete);
  return res;

} /* dvd_title_get */

int dvd_title_create(dvd_title *title_record_to_add, int *title_id) {
  int result;

  if (!pg_check_db_is_connected("dvd_title_create")) return DVD_ERR_NO_FILE;

  if(title_record_to_add == NULL || title_id == NULL) return DVD_ERR_NULL_POINTER;
  result = pg_title_insert(title_record_to_add);

  if (result == DVD_SUCCESS) {
    *title_id = title_record_to_add->title_id;
  }
  return result;

} /* dvd_title_create */

int dvd_title_delete(const int title_id) {
  int *results;
  int count;
  int i;


  if (!pg_check_db_is_connected("dvd_title_delete")) return DVD_ERR_NO_FILE;

  if (dvd_disk_search(title_id, &results, &count) == DVD_SUCCESS) {
    for(i = 0; i < count; i++) {
      (void)pg_disk_delete(results[i]);
    }
    free(results);
  }
  
  return pg_title_delete(title_id);
} /* dvd_title_delete */

int dvd_title_search(const char *title, const char *name, int *result_ids[], int *count) {

  if (!pg_check_db_is_connected("dvd_title_search")) return DVD_ERR_NO_FILE;
  if (count == NULL) return DVD_ERR_NULL_POINTER;
  if ((name == NULL)  && (title == NULL)) return DVD_ERR_NULL_POINTER;

  return pg_title_search(title, name, result_ids, count);

} /* dvd_title_search */


int dvd_disk_set(const dvd_disk *disk_record_to_update) {
  int res;

  if (!pg_check_db_is_connected("dvd_disk_set")) return DVD_ERR_NO_FILE;

  if(disk_record_to_update == NULL) return DVD_ERR_NULL_POINTER;

  res = pg_disk_set(disk_record_to_update);
  return res;

} /* dvd_disk_set */

int dvd_disk_get(const int disk_id, dvd_disk *disk_record_to_complete) {

  int res;

  if (!pg_check_db_is_connected("dvd_disk_get")) return DVD_ERR_NO_FILE;
  if(disk_record_to_complete == NULL) return DVD_ERR_NULL_POINTER;
  
  res = pg_disk_get(disk_id, disk_record_to_complete);
  return res;

} /* dvd_disk_get */

int dvd_disk_create(dvd_disk *disk_record_to_add, int *disk_id) {
  int result;

  if (!pg_check_db_is_connected("dvd_disk_create")) return DVD_ERR_NO_FILE;
  if(disk_record_to_add == NULL) return DVD_ERR_NULL_POINTER;
  result = pg_disk_insert(disk_record_to_add);

  if (result == DVD_SUCCESS) {
    *disk_id = disk_record_to_add->disk_id;
  }
  return result;

} /* dvd_disk_create */

int dvd_disk_delete(const int disk_id) {
  int res;

  if (!pg_check_db_is_connected("dvd_disk_delete")) return DVD_ERR_NO_FILE;

  res = pg_disk_delete(disk_id);
  return res;
} /* dvd_disk_delete */

int dvd_disk_search(const int title_id, int *result_ids[], int *count) {

  if (!pg_check_db_is_connected("dvd_disk_search")) return DVD_ERR_NO_FILE;
  return pg_disk_search(title_id, result_ids, count);

} /* dvd_disk_search */


int dvd_get_genre_list(char **genre_list[], int *count) {
  int res;

  if (!pg_check_db_is_connected("dvd_get_genre_list")) return DVD_ERR_NO_FILE;
  res = pg_get_genre_list(genre_list, count);
  return res;
} /* dvd_get_genre_list */

int dvd_get_classification_list(char **class_list[], int *count) {

  int res;

  if (!pg_check_db_is_connected("dvd_classification_list")) return DVD_ERR_NO_FILE;
  res = pg_get_class_list(class_list, count);
  return res;

} /* dvd_get_classification_list */



int dvd_err_text(const int err_number, char **message_to_show) {

  if (!pg_check_db_is_connected("dvd_err_text")) return DVD_ERR_NO_FILE;
  pg_get_err_text(err_number, message_to_show);
  return DVD_SUCCESS;

} /* dvd_err_text */


int dvd_today(char **date) {
  static char today[9];
  time_t the_ticks = time(NULL);
  struct tm *the_time = localtime(&the_ticks);
  sprintf(today, "%04d%02d%02d",
	  the_time -> tm_year + 1900,
	  the_time -> tm_mon + 1,
	  the_time -> tm_mday);
  *date = today;
  return DVD_SUCCESS;
} /* dvd_today */

int dvd_rent_title(const int member_id, const int title_id, int *disk_id) {
  int res;
  char *today_date;
  int count;
  int title_rented;

  if (!pg_check_db_is_connected("dvd_rent_title")) return DVD_ERR_NO_FILE;
  if (disk_id == NULL) return DVD_ERR_NULL_POINTER;
  
  (void)dvd_today(&today_date);

  /* Check first if the member has it reserved */
  res = pg_reserve_title_query_by_member(member_id, &title_rented);

  if (res != DVD_SUCCESS) {
    *disk_id = 0;
    return res;
  }

  if (title_id == title_rented) {
    /* release the reservation */
    (void)pg_reserve_title_cancel(member_id);
  } else {
    /* it it available anyway */
    res = pg_title_available(title_id, today_date, &count);
    if (res != DVD_SUCCESS) {
      *disk_id = 0;
      return res;
    }

    if (count <= 0) {
      *disk_id = 0;
      return DVD_ERR_NOT_FOUND;
    }
  }
  /* now pick a disk to rent */
  res = pg_rent_disk(member_id, title_id, today_date, disk_id);
  return res;

} /* dvd_rent_title */

int dvd_rented_disk_info(const int disk_id, int *member_id, char *date_rented) {

  if (!pg_check_db_is_connected("dvd_rented_disk_info")) return DVD_ERR_NO_FILE;

  if (!member_id || !date_rented) return DVD_ERR_NULL_POINTER;
  return pg_rented_disk_info(disk_id, member_id, date_rented);
} /* dvd_rented_disk_info */

int dvd_disk_return(const int disk_id, int *member_id, char *date) {
  if (!member_id || !date) return DVD_ERR_NULL_POINTER;
  return pg_disk_return(disk_id, member_id, date);
} /* dvd_disk_return */

int dvd_overdue_disks(const char *date1, const char *date2, int *disk_ids[], int *count) {
  char my_date1[9];
  char my_date2[9];
  struct tm *the_time;

  if (!pg_check_db_is_connected("dvd_overdue_disks")) return DVD_ERR_NO_FILE;
  if (date1 == NULL) { /* => since epoch */
    strcpy(my_date1, "19700101"); /* there where no DVD stores before this! */
  } else {
    strcpy(my_date1, date1);
  }
  if (date2 == NULL) {  /* => tomorrow */
    time_t the_ticks = time(NULL);
    the_ticks += 86400L; /* 86400 = 60*60*24 to move to tomorrow */

    the_time = localtime(&the_ticks);
    sprintf(my_date2, "%04d%02d%02d", the_time -> tm_year + 1900,
	    the_time -> tm_mon + 1, the_time -> tm_mday);
  } else {
    strcpy(my_date2, date2);
  }

  return pg_overdue_disks(my_date1, my_date2, disk_ids, count);
    
} /* dvd_overdue_disks */

int dvd_title_available(const int title_id, const char *date, int *count) {
  int res;
  
  if (!pg_check_db_is_connected("dvd_title_available")) return DVD_ERR_NO_FILE;
  if (!date || !count) return DVD_ERR_NULL_POINTER;
  res = pg_title_available(title_id, date, count);
  return res;

} /* dvd_title_available */

/* This is slightly unfriendly, in that we cancel prior reservations before checking if the later reservation succeeds */
int dvd_reserve_title(const char *date, const int title_id, int member_id) {
  int count;

  if (!pg_check_db_is_connected("dvd_reserve_title")) return DVD_ERR_NO_FILE;

  if (!date) return DVD_ERR_NULL_POINTER;
  (void)pg_reserve_title_cancel(member_id);
  
  if (dvd_title_available(title_id, date, &count) == DVD_SUCCESS) {
    if (count > 0) {
      return pg_make_reservation(title_id, date, member_id);
    }
  }
  return DVD_ERR_NOT_FOUND;
} /* dvd_reserve_title */

int dvd_reserve_title_cancel(const int member_id) {
  if (!pg_check_db_is_connected("dvd_reserve_title_cancel")) return DVD_ERR_NO_FILE;
  return pg_reserve_title_cancel(member_id);
} /* dvd_reserve_title_cancel */

int dvd_reserve_title_query_by_member(const int member_id, int *title_id) {
  if (!pg_check_db_is_connected("dvd_reserve_title_query_by_member")) return DVD_ERR_NO_FILE;
  return pg_reserve_title_query_by_member(member_id, title_id);
} /* dvd_reserve_title_query_by_member */

int dvd_reserve_title_query_by_titledate(const int title_id, const char *date, int *member_ids[], int *count) {

  if (!pg_check_db_is_connected("dvd_reserve_title_query_by_titledate")) return DVD_ERR_NO_FILE;
  return pg_reserve_title_query_by_titledate(title_id, date, member_ids, count);
} /* dvd_reserve_title_query_by_titledate */



static void trim_member(dvd_store_member *a_member) {
  string_trim(a_member->member_no, sizeof(a_member->member_no));
  string_trim(a_member->title, sizeof(a_member->title));
  string_trim(a_member->fname, sizeof(a_member->fname));
  string_trim(a_member->lname, sizeof(a_member->lname));
  string_trim(a_member->house_flat_ref, sizeof(a_member->house_flat_ref));
  string_trim(a_member->address1, sizeof(a_member->address1));
  string_trim(a_member->address2, sizeof(a_member->address2));
  string_trim(a_member->town, sizeof(a_member->town));
  string_trim(a_member->state, sizeof(a_member->state));
  string_trim(a_member->phone, sizeof(a_member->phone));
  string_trim(a_member->zipcode, sizeof(a_member->zipcode));

} /* trim_member */

static void trim_title(dvd_title *a_title) {
  string_trim(a_title->title_text, sizeof(a_title->title_text));
  string_trim(a_title->asin, sizeof(a_title->asin));
  string_trim(a_title->director, sizeof(a_title->director));
  string_trim(a_title->genre, sizeof(a_title->genre));
  string_trim(a_title->classification, sizeof(a_title->classification));
  string_trim(a_title->actor1, sizeof(a_title->actor1));
  string_trim(a_title->actor2, sizeof(a_title->actor2));
  string_trim(a_title->release_date, sizeof(a_title->release_date));
  string_trim(a_title->rental_cost, sizeof(a_title->rental_cost));

} /* trim_title */

void string_trim(char *str_tt, int len) {
  
  char *str_end;
  char *str_start = str_tt;
  str_end = str_start;
  str_end += len;
  str_end -= 2;

  while ((*str_end == ' ') && (str_end >= str_start)) {
    *str_end = '\0';
    str_end--;
  }

} /* string_trim */





