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

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

  Main Header File

*/

/* Error definitions */
#define DVD_SUCCESS                 0
#define DVD_ERR_NO_FILE            -1
#define DVD_ERR_BAD_TABLE          -2
#define DVD_ERR_NO_MEMBER_TABLE    -3
#define DVD_ERR_BAD_MEMBER_TABLE   -4
#define DVD_ERR_BAD_TITLE_TABLE    -5
#define DVD_ERR_BAD_DISK_TABLE     -6
#define DVD_ERR_BAD_SEEK           -7
#define DVD_ERR_NULL_POINTER       -8
#define DVD_ERR_BAD_WRITE          -9
#define DVD_ERR_BAD_READ          -10
#define DVD_ERR_NOT_FOUND         -11
#define DVD_ERR_NO_MEMORY         -12
#define DVD_ERR_BAD_RENTAL_TABLE  -13
#define DVD_ERR_BAD_RESERVE_TABLE -14
#define DVD_ERR_BAD_DATABASE      -15
#define DVD_ERR_BAD_GENRE         -16

/*
General note:
All _id fields will have 0 reserved, so that it can be used as a 
sentinel value in arrays if required.
*/

/*
  Initialise the database

  Applications MUST call either dvd_open_db OR dvd_open_db_login
  before any other accesses, and dvd_close_db MUST be called before
  exiting your application.
*/

int dvd_open_db(void);
int dvd_open_db_login(const char *user, const char *password);
int dvd_close_db(void);

/* 
  Fixed lengths are generally used in the API structures. This is done
  to keep the API simple, since it's purpose is to provide a demonstration
  application, not be the specification for an application
  that is functionally complete and ready to use out of the box.

  Lengths include the null terminator.

*/
#define MEMBER_KNOWN_ID_LEN		6
#define PERSON_TITLE_LEN		4
#define NAME_LEN			26
#define ADDRESS_LEN			51
#define STATE_LEN			3
#define PHONE_NO_LEN			31
#define ZIP_CODE_LEN			11
#define DVD_TITLE_LEN			61
#define ASIN_LEN			11
#define GENRE_LEN			21
#define CLASS_LEN			11
#define DAY_DATE_LEN			9
#define COST_LEN			7

/*
  The member structure
*/

typedef struct {
	int member_id; 				/* internal id [1..] */
	char member_no[MEMBER_KNOWN_ID_LEN];	/* the number the member knows */
	char title[PERSON_TITLE_LEN];		/* Mr Mrs Ms Dr Sir */
	char fname[NAME_LEN];			/* first name */
	char lname[NAME_LEN];			/* last name */
	char house_flat_ref[NAME_LEN];		/* i.e. 5, or 'The birches' etc. */
	char address1[ADDRESS_LEN];		/* Address line 1 */
	char address2[ADDRESS_LEN];		/* Address line 2 */
	char town[ADDRESS_LEN];			/* Town/City */
        char state[STATE_LEN];			/* needed in US only */
	char phone[PHONE_NO_LEN];		/* +44(0)123 456789 */
	char zipcode[ZIP_CODE_LEN];		/* LE1 1AA or whatever */
} dvd_store_member;

/*
Notice that we separate the 'member number' that the member actually
knows, from an internal integer that we can generate and use
internally. This will be handy if we ever want to give the system to a
store using alpha-numeric membership codes. We will do the same for
disks and titles.

Here is the information for a DVD title.  
*/

typedef struct {
	int title_id;				/* internal ID [1..] */
	char title_text[DVD_TITLE_LEN];		/* 'The silence of the lambs' */
	char asin[ASIN_LEN];			/* 10 digit reference number */
	char director[NAME_LEN];		/* restricted to a single name */
	char genre[GENRE_LEN];			/* 'Horror', 'comedy', etc. API for standard list later */
	char classification[CLASS_LEN];		/* API for standard list later */
	char actor1[NAME_LEN];			/*  'Jeremy Irons' */
	char actor2[NAME_LEN];			/* 'Ingmar Bergman' */
	char release_date[DAY_DATE_LEN];	/* YYYYMMDD plus the null */
	char rental_cost[COST_LEN];		/* cost of a day rental for this title $$$.cc */
} dvd_title;

/*
The information for a DVD disk is much simpler:
*/

typedef struct {
	int disk_id;			/* internal ID [1..] (not related to title_id) */
	int title_id;			/* the title_id of which this is an instance */
} dvd_disk;

/*

All dates will be stored in the format "YYYYMMDD".
All character arrays and strings passed will be null terminated.
enum will be defined for error codes (and 0 for success).


Before we can consider the APIs for providing our functionality, we
need to make an important decision about how we handle results that
need to return multiple instances of data, for example searching on a
DVD title could return zero, one or many titles. For example a search
on member, that returned 12000 members is going to be roughly 2M of
data. Whilst this is manageable locally, it's not sensible to return
that much data to any sort of remote client in one go. On the other
hand, providing a scrolling mechanism that can cater for multiple
clients scrolling through different sub-sets of different query
results is going to result in a complex API that may not be very
flexible for the future.

Our solution is to decide that our API will simply return all the data
in one hit, and pass the responsibility for catering for remote
clients that might need per-client data management to any application
that need this responsibility.

Let's get the  simple get and set APIs defined first.  In all cases we
use int functions, so we can return 0 for success or a negative number
as  an error  code. [Will  define an  enum set  for the  return codes,
including a  zero for OK later].  Where the result size  is fixed, the
calling  party  is always  responsible  for  memory management,  where
result size is not fixed  the called routine allocates memory with malloc,
and the calling routine is then responsible for freeing it with free.
[Note that search routines return 0 for success, even if this is no data,
all search APIs that return multiple results provide a count output
to indicate the number of items in the returned array.]

[To make this all fall out in multi-user mode, all the APIs are
'single shot' type, so there is no session or content type information
needed in the back end API.]

Search APIs are not very generic, but make life simpler, since the purpose
is to demonstrate the principals, not completly solve the generic problem.

Deletion will do cascade deletes, so deleting a title deletes the
disks, rental records [etc. etc. ]

*/

/*
  Member APIs

  To create a new member, pass a partially complete dvd_store_member
  to dvd_member_create. The member_id and member_no fields are not
  required. A freshly allocated member_id is passed back in the output
  parameter member_id. This is used to retrieve the member details
  thereafter. The membership "number" given to the new member (may be
  written on his membership card) is generated and stored in the member_no
  field - in the database. The passed-in structure may be altered by
  dvd_member_create. A typcal use of dvd_member_create would be followed
  by a dvd_member_get to fetch the now-complete member record, indexed
  by the returned (new) member_id.

  Member details can be updated by a dvd_member_get/set pair. Do not
  attempt to alter the member_id field.

  Members are deleted with a call to dvd_member_delete passing a member id.
*/

int dvd_member_set(const dvd_store_member *member_record_to_update);
int dvd_member_get(const int member_id, dvd_store_member *member_record_to_complete);
int dvd_member_create(dvd_store_member *member_record_to_add, int *member_id);
int dvd_member_delete(const int member_id);

/*
  Member search APIs

  To find a member given the membership number (as on member's card)
  call dvd_member_get_id_from_number.

  To find a member given part of a last name use dvd_member_search.
  In this case the results are returned as a count and an array of
  member ids. The array must be deallocated by a call to free().
  The search performs a sub-string match on the lname member field.
*/ 

int dvd_member_search(const char *lname, int *result_ids[], int *count);
int dvd_member_get_id_from_number(const char *member_no, int *member_id);

/*
  DVD Title APIs

  These APIs function in an entirely similar way to members.
  The dvd_title_search is currently an either-or on substrings
  within film title text(title) and directors/actors(name).
*/

int dvd_title_set(const dvd_title *title_record_to_update);
int dvd_title_get(const int title_id, dvd_title *title_record_to_complete);
int dvd_title_create(dvd_title *title_record_to_add, int *title_id);
int dvd_title_delete(const int title_id);
int dvd_title_search(const char *title, const char *name, int *result_ids[], int *count);

/*
  Disk APIs

  These APIs are used for manipulating the record of physical
  DVD disks, each of which is an instance of a title.
*/

int dvd_disk_set(const dvd_disk *disk_record_to_update);
int dvd_disk_get(const int disk_id, dvd_disk *disk_record_to_complete);
int dvd_disk_create(dvd_disk *disk_record_to_add, int *disk_id);
int dvd_disk_delete(const int disk_id);
int dvd_disk_search(const int title_id, int *result_ids[], int *count);

/*
We also need some utility type APIs, mostly to fetch 'fixed' data from
defining tables in the database. This data is 'read-only', the pointers
returned will address static data areas. They must not be freed by the caller! 
*/
/* return the valid of genres: comedy, thriller etc. */
int dvd_get_genre_list(char **genre_list[], int *count); 
/* return the valid of classes: U, PG etc. */
int dvd_get_classification_list(char **class_list[], int *count);
int dvd_err_text(const int err_number, char **message_to_show); /* given error return from our API, get some text */
int dvd_today(char **date); /* get today's date as YYYYMMDD */

/*
The extra functions we need are:

Do a rental of one or more titles in a single sale, giving a total
cost Check the availability of a title on a particular date.  Do a
return of disks (one at a time is fine, don't care if they were rented
as a set) Reserve a title for a particular date.  Report overdue
returns
*/

/*
 Given a member ID and a title, rent out a disk and return
 a suitable physical disk ID to provide to the customer.
 The cost should be found by getting the title information first.
*/
int dvd_rent_title(const int member_id, const int title_id, int *disk_id);

/* Return information about a disk, whether rented out and to whom */
int dvd_rented_disk_info(const int disk_id, int *member_id, char *date_rented);

/* Return a disk - give the date it was rented in case it's overdue */
int dvd_disk_return(const int disk_id, int *member_id, char *date);

/* Return a list of disks rented after (>=) date1 and before (<) date2 */
/* Null dates mean pre-history and tomorrow */
int dvd_overdue_disks(const char *date1, const char *date2, int *disk_ids[], int *count);

/* How many copies of a title are available on a given day */
int dvd_title_available(const int title_id, const char *date, int *count);

/* Make a reservation for a title on a given date */
/* Only one reservation per member at a time - will clobber a previous one */
int dvd_reserve_title(const char *date, const int title_id, const int member_id);

/* Cancel a reservation - do this before renting a reserved title */
int dvd_reserve_title_cancel(const int member_id);

/* Given a member, return which title he has reserved */
int dvd_reserve_title_query_by_member(const int member_id, int *title_id);

/* 
   Return a list of members with reservations for a particular title on
   a given date
*/
int dvd_reserve_title_query_by_titledate(const int title_id, const char *date, int *member_ids[], int *count);










