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

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.

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



/*
  Test Program for the DVD store APIs
*/

#include <stdlib.h>
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <string.h>
#include "dvd.h"

int show_result(char *, int);
int execute_command(char *);
void initialize_readline(void);

int main()
{
  char *command;

  printf("DVD Store Application\n");

  show_result("open db", dvd_open_db());

  /* Do not open the database, so we can test */
  /* printf("Warning, database is not open\n"); */

  /* Set up the command line interface */
  initialize_readline();

  /* Main loop, read commands and execute them */
  while(1) {
    command = readline("> ");
    if(command == NULL)
      break;
    if(*command != '\0') {
      add_history(command);
      (void) show_result("!", execute_command(command));
    }
    free(command);
  }  
  exit(EXIT_SUCCESS);
}

int show_result(char *msg, int err)
{
  char *err_msg = "unable to obtain error text";

  (void) dvd_err_text(err, &err_msg);
  printf("%s: %s\n", msg, err_msg);
  return err == DVD_SUCCESS;
}

int help_function(int argc, char *argv[]);
int quit_function(int argc, char *argv[]);
int classes_function(int argc, char *argv[]);
int genres_function(int argc, char *argv[]);
int errtext_function(int argc, char *argv[]);
int today_function(int argc, char *argv[]);
int member_function(int argc, char *argv[]);
int title_function(int argc, char *argv[]);
int disk_function(int argc, char *argv[]);
int rent_function(int argc, char *argv[]);
int connect_function(int argc, char *argv[]);

typedef int Func(int, char **);

struct {
  char *name;
  Func *func;
  char *help;
} functions[] = {
  {"help", help_function, "summary of functions"},
  {"quit", quit_function, "quit the application"},
  {"classes", classes_function, "get classification list"},
  {"genres", genres_function, "get genres list"},
  {"err", errtext_function, "get error message from number"},
  {"today", today_function, "get current date"},
  {"member", member_function, "create, set, get, search members"},
  {"title", title_function, "create, set, get, search titles"},
  {"disk", disk_function, "create, set, get, search disks"},
  {"rent", rent_function, "rent, return and reserve disks"},
  {"connect", connect_function, "connect and disconnect from database"},
  {NULL, NULL}
};

int help_function(int argc, char *argv[])
{
  int f;

  printf("These functions are available:\n");
  for(f = 0; functions[f].name; f++)
    printf("%s \t%s\n", functions[f].name, functions[f].help);
  printf("To get more help try <command> help\n");

  return DVD_SUCCESS;
}

int quit_function(int argc, char *argv[])
{
  dvd_close_db();
  exit(EXIT_SUCCESS);
}

int classes_function(int argc, char *argv[])
{
  char **classes;
  int count;
  
  if(argc != 1)
    return DVD_ERR_NOT_FOUND;

  if(show_result("classes", dvd_get_classification_list(&classes, &count))) {
    int i = 0;
    for(i = 0; i < count; i++)
      printf("[%s]",classes[i]);
    printf("\n");
  }
  return DVD_SUCCESS;
}

int genres_function(int argc, char *argv[])
{
  char **genres;
  int count;
  
  if(argc != 1)
    return DVD_ERR_NOT_FOUND;

  if(show_result("genres", dvd_get_genre_list(&genres, &count))) {
    int i = 0;
    for(i = 0; i < count; i++)
      printf("[%s]",genres[i]);
    printf("\n");
  }
  return DVD_SUCCESS;
}

int errtext_function(int argc, char *argv[])
{
  char *msg;
  int err;

  if(argc != 2)
    return DVD_ERR_NOT_FOUND;

  if(argv[1][0] == '-')
    err = -atoi(&argv[1][1]);
  else
    err = atoi(argv[1]);

  dvd_err_text(err, &msg);
  printf("[%s]\n", msg);
  return DVD_SUCCESS;
}

int today_function(int argc, char *argv[])
{
  char *date;

  if(argc != 1)
    return DVD_ERR_NOT_FOUND;

  if(show_result("err", dvd_today(&date)))
     printf("[%s]\n", date);

  return DVD_SUCCESS;
}

void print_member(dvd_store_member *m)
{
  printf("DVD Member #%d(%s):\n", m -> member_id, m -> member_no);
  printf("%s %s %s\n", m -> title, m -> fname, m -> lname);
  printf("%s %s %s\n", m -> house_flat_ref, m -> address1, m -> address2);
  printf("%s %s %s\n", m -> town, m -> state, m -> zipcode);
  printf("Tel: %s\n", m -> phone);
}

int member_function(int argc, char *argv[])
{
  if(argc < 2)
    return DVD_ERR_NOT_FOUND;

  if(argc == 2 && strcmp(argv[1], "help") == 0) {
    printf("member get    id\n");
    printf("member delete id\n");
    printf("member create number,title,fname,lname,house,addr1,addr1,town,state,code,phone\n");
    printf("member set    id,number,title,fname,lname,house,addr1,addr1,town,state,code,phone\n");
    printf("member search lastname\n");
    printf("member number number\n");
  }

  if(argc == 3 && strcmp(argv[1], "get") == 0) {
    dvd_store_member m;
    if(show_result("member get", dvd_member_get(atoi(argv[2]), &m)))
      print_member(&m);
  }

  if(argc == 3 && strcmp(argv[1], "delete") == 0) {
    show_result("member delete", dvd_member_delete(atoi(argv[2])));
  }

  if(argc == 13 && strcmp(argv[1], "create") == 0) {
    dvd_store_member m;
    int id = -1;

    strcpy(m.member_no, argv[2]);
    strcpy(m.title, argv[3]);
    strcpy(m.fname, argv[4]);
    strcpy(m.lname, argv[5]);
    strcpy(m.house_flat_ref, argv[6]);
    strcpy(m.address1, argv[7]);
    strcpy(m.address2, argv[8]);
    strcpy(m.town, argv[9]);
    strcpy(m.state, argv[10]);
    strcpy(m.zipcode, argv[11]);
    strcpy(m.phone, argv[12]);

    if(show_result("member create", dvd_member_create(&m, &id)))
      printf("[%d]\n", id);
  }
  
  if(argc == 14 && strcmp(argv[1], "set") == 0) {
    dvd_store_member m;
    m.member_id = atoi(argv[2]);
    strcpy(m.member_no, argv[3]);
    strcpy(m.title, argv[4]);
    strcpy(m.fname, argv[5]);
    strcpy(m.lname, argv[6]);
    strcpy(m.house_flat_ref, argv[7]);
    strcpy(m.address1, argv[8]);
    strcpy(m.address2, argv[9]);
    strcpy(m.town, argv[10]);
    strcpy(m.state, argv[11]);
    strcpy(m.zipcode, argv[12]);
    strcpy(m.phone, argv[13]);

    show_result("member set", dvd_member_set(&m));
  }

  if(argc == 3 && strcmp(argv[1], "number") == 0) {
    int id;

    if(show_result("member number", dvd_member_get_id_from_number(argv[2], &id)))
      printf("[%d]\n", id);
  }
  
  if(argc == 3 && strcmp(argv[1], "search") == 0) {
    int count;
    int *results;
    int i;
    
    show_result("member search",
		dvd_member_search(argv[2], &results, &count));
    for(i = 0; i < count; i++)
      printf("[%d]",results[i]);
    printf("\n");
  }
  else {
    return DVD_ERR_NOT_FOUND;
  }
  return DVD_SUCCESS;
}

void print_title(dvd_title *dvd)
{
  printf("DVD Title #%d: %s\n", dvd -> title_id, dvd -> title_text);
  printf("Directed by %s (%s), Rated: %s, %s\n", dvd -> director,
	 dvd -> release_date, dvd -> classification, dvd -> genre);
  printf("Starring: %s %s\n", dvd -> actor1, dvd -> actor2);
  printf("ASIN %s, Price %s\n", dvd -> asin, dvd -> rental_cost);
}

int title_function(int argc, char *argv[])
{
  if(argc < 2)
    return DVD_ERR_NOT_FOUND;

  if(argc == 2 && strcmp(argv[1], "help") == 0) {
    printf("title get    id\n");
    printf("title delete id\n");
    printf("title create title,asin,director,genre,class,actor1,actor2,date,cost\n");
    printf("title set    id,title,asin,director,genre,class,actor1,actor2,date,cost\n");
    printf("title search title,name\n");
  }

  if(argc == 3 && strcmp(argv[1], "get") == 0) {
    dvd_title dvd;
    if(show_result("title get", dvd_title_get(atoi(argv[2]), &dvd)))
      print_title(&dvd);
  }

  if(argc == 3 && strcmp(argv[1], "delete") == 0) {
    show_result("title delete", dvd_title_delete(atoi(argv[2])));
  }

  if(argc == 11 && strcmp(argv[1], "create") == 0) {
    dvd_title dvd;
    int id = -1;

    strcpy(dvd.title_text, argv[2]);
    strcpy(dvd.asin, argv[3]);
    strcpy(dvd.director, argv[4]);
    strcpy(dvd.genre, argv[5]);
    strcpy(dvd.classification, argv[6]);
    strcpy(dvd.actor1, argv[7]);
    strcpy(dvd.actor2, argv[8]);
    strcpy(dvd.release_date, argv[9]);
    strcpy(dvd.rental_cost, argv[10]);
    if(show_result("title create", dvd_title_create(&dvd, &id)))
      printf("[%d]\n", id);
  }
  
  if(argc == 12 && strcmp(argv[1], "set") == 0) {
    dvd_title dvd;
    dvd.title_id = atoi(argv[2]);
    strcpy(dvd.title_text, argv[3]);
    strcpy(dvd.asin, argv[4]);
    strcpy(dvd.director, argv[5]);
    strcpy(dvd.genre, argv[6]);
    strcpy(dvd.classification, argv[7]);
    strcpy(dvd.actor1, argv[8]);
    strcpy(dvd.actor2, argv[9]);
    strcpy(dvd.release_date, argv[10]);
    strcpy(dvd.rental_cost, argv[11]);
    show_result("title set", dvd_title_set(&dvd));
  }
  
  if(argc == 4 && strcmp(argv[1], "search") == 0) {
    int count;
    int *results;
    int i;
    
    show_result("title search",
		dvd_title_search(argv[2], argv[3], &results, &count));
    for(i = 0; i < count; i++)
      printf("[%d]",results[i]);
    printf("\n");
  }
  else {
    return DVD_ERR_NOT_FOUND;
  }
  return DVD_SUCCESS;
}

void print_disk(dvd_disk *d)
{
  dvd_title dvd;
  printf("DVD Disk #%d (title %d):\n", d -> disk_id, d -> title_id);
  if(dvd_title_get(d -> title_id, &dvd) == DVD_SUCCESS)
    printf("%s\n", dvd.title_text);
  else
    printf("Invalid Title?\n");
}

int disk_function(int argc, char *argv[])
{
  if(argc < 2)
    return DVD_ERR_NOT_FOUND;

  if(argc == 2 && strcmp(argv[1], "help") == 0) {
    printf("disk get    id\n");
    printf("disk delete id\n");
    printf("disk create title_id\n");
    printf("disk set    id,title_id\n");
    printf("disk search title_id\n");
  }

  if(argc == 3 && strcmp(argv[1], "get") == 0) {
    dvd_disk d;
    if(show_result("disk get", dvd_disk_get(atoi(argv[2]), &d)))
      print_disk(&d);
  }

  if(argc == 3 && strcmp(argv[1], "delete") == 0) {
    show_result("disk delete", dvd_disk_delete(atoi(argv[2])));
  }

  if(argc == 3 && strcmp(argv[1], "create") == 0) {
    dvd_disk d;
    int id = -1;

    d.title_id = atoi(argv[2]);

    if(show_result("disk create", dvd_disk_create(&d, &id)))
      printf("[%d]\n", id);
  }
  
  if(argc == 4 && strcmp(argv[1], "set") == 0) {
    dvd_disk d;
    d.disk_id = atoi(argv[2]);
    d.title_id = atoi(argv[3]);

    show_result("disk set", dvd_disk_set(&d));
  }

  if(argc == 3 && strcmp(argv[1], "search") == 0) {
    int count;
    int *results;
    int i;
    
    show_result("disk search",
		dvd_disk_search(atoi(argv[2]), &results, &count));
    for(i = 0; i < count; i++)
      printf("[%d]",results[i]);
    printf("\n");
  }
  else {
    return DVD_ERR_NOT_FOUND;
  }
  return DVD_SUCCESS;
}

int rent_function(int argc, char *argv[])
{
  int member_id;
  int title_id;
  int disk_id;
  int count;

  if(argc < 2)
    return DVD_ERR_NOT_FOUND;

  if(argc == 2 && strcmp(argv[1], "help") == 0) {
    printf("rent title    member_id,title_id\n");
    printf("rent return   disk_id\n");
    printf("rent info     disk_id\n");
    printf("rent avail    title_id,date\n");
    printf("rent reserve  member_id,title_id,date\n");
    printf("rent cancel   member_id\n");
    printf("rent query    member_id\n");
    printf("rent date     title_id,date\n");
    printf("rent due      date1,date2\n");
  }

  if(argc == 4 && strcmp(argv[1], "title") == 0) {
    member_id = atoi(argv[2]);
    title_id = atoi(argv[3]);

    if(show_result("rent title", dvd_rent_title(member_id,title_id,&disk_id)))
      printf("[%d]\n",disk_id);
  }

  if(argc == 3 && strcmp(argv[1], "return") == 0) {
    char date[9];
    disk_id = atoi(argv[2]);
    if(show_result("rent return", dvd_disk_return(disk_id,&member_id,date)))
      printf("[%d][%s]\n",member_id,date);
  }

  if(argc == 3 && strcmp(argv[1], "info") == 0) {
    char date[9];
    disk_id = atoi(argv[2]);
    if(show_result("rent info", dvd_rented_disk_info(disk_id,&member_id,date)))
      printf("[%d][%s]\n",member_id,date);
  }

  if(argc == 4 && strcmp(argv[1], "avail") == 0) {
    title_id = atoi(argv[2]);
    if(show_result("rent reserve", dvd_title_available(title_id,argv[3],&count)))
       printf("[%d]\n", count);
  }

  if(argc == 5 && strcmp(argv[1], "reserve") == 0) {
    member_id = atoi(argv[2]);
    title_id = atoi(argv[3]);
    show_result("rent reserve", dvd_reserve_title(argv[4],title_id,member_id));
  }

  if(argc == 3 && strcmp(argv[1], "cancel") == 0) {
    member_id = atoi(argv[2]);
    show_result("rent cancel", dvd_reserve_title_cancel(member_id));
  }

  if(argc == 3 && strcmp(argv[1], "query") == 0) {
    member_id = atoi(argv[2]);
    if(show_result("rent query", dvd_reserve_title_query_by_member(member_id,&title_id)))
      printf("[%d]\n",title_id);
  }

  if(argc == 4 && strcmp(argv[1], "date") == 0) {
    int *members;
    int i;
    title_id = atoi(argv[2]);
    
    show_result("rent date",
		dvd_reserve_title_query_by_titledate(title_id,argv[3],&members,&count));
    for(i = 0; i < count; i++)
      printf("[%d]",members[i]);
    printf("\n");
  }

  if(argc == 4 && strcmp(argv[1], "due") == 0) {
    int *results;
    int i;
    
    show_result("rent due",
		dvd_overdue_disks(argv[2],argv[3], &results, &count));
    for(i = 0; i < count; i++)
      printf("[%d]",results[i]);
    printf("\n");
  }
  return DVD_SUCCESS;
}

int connect_function(int argc, char *argv[])
{

  if(argc == 2 && strcmp(argv[1], "help") == 0) {
    printf("connect\n");
    printf("connect login user,password\n");
    printf("connect logout\n");
  }

  if(argc == 1) {
    show_result("open db", dvd_open_db());
  }

  if(argc == 4 && strcmp(argv[1], "login") == 0) {
    show_result("connect login", dvd_open_db_login(argv[2], argv[3]));
  }

  if(argc == 2 && strcmp(argv[1], "logout") == 0) {
    show_result("connect logout", dvd_close_db());
  }
  return DVD_SUCCESS;
}

int execute_command(char *command)
{
  /* Break the command into comma separated tokens */
  char *string = command;
  char *token;
  char *items[20];
  int item = 0, i;
  char *cmd1, *cmd2;
  int f;

  /* Commands consist of either a single command word
     or two words followed by a comma separated list of args */

  cmd1 = strsep(&string, " ");
  items[item++] = cmd1;

  cmd2 = strsep(&string, " ");
  if(cmd2 == NULL)
    items[item] = NULL;
  else
    items[item++] = cmd2;

  if(cmd2) {
    /* Split up the arguments */
    while(1) {
      token = strsep(&string,",");
      if(token == NULL) {
	/* Last one */
	/* items[item++] = string; */
	break;
      }
      else
	items[item++] = token;
    };
    
    items[item] = NULL;
  }

  for(i = 0; i < item; i++)
    printf("[%s]", items[i]);
  printf("\n");

  /* Now call the right function for cmd1 */
  for(f = 0; functions[f].name != NULL; f++) {
    if(strcmp(cmd1, functions[f].name) == 0) {
      (*functions[f].func)(item, items);
      break;
    }
  }
  if(functions[f].name == NULL)
    return DVD_ERR_NOT_FOUND;

  return DVD_SUCCESS;
}

void initialize_readline()
{
  /* Turn off TAB file completion */
  rl_bind_key('\t', rl_insert);
}
