/* -*- Syntax: Ansi-C; Base: 10; Mode: c; -*- 

 Buyer.c

 A simple buyer agent...

 The FishMarket project...

 Francisco J. Martin & Juan A. Rodriguez
 {martin,jar}@iiia.csic.es

 Copyright (c) 1997  by the 
 Institut d'Investigacion en Intel.ligencia Artificial (IIIA), CSIC
 Campus de la Universitat Autonoma de Barcelona
 08193 Bellaterra, Barcelona, Spain
  
    
   Permission to use, copy, modify, and distribute this software and its
   documentation for any purpose and without fee is hereby granted,
   provided that this copyright and permission notice appear in all
   copies and supporting documentation, and that the name of IIIA-CSIC not
   be used in advertising or publicity pertaining to distribution of the
   software without specific, written prior permission. IIIA-CSIC makes no
   representations about the suitability of this software for any
   purpose.  It is provided "as is" without express or implied warranty.
          
   IIIA-CSIC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
   IIIA-CSIC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
   WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
   ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   SOFTWARE.
                   
 Created: 1996 09 22 17:11

 Last modification: 1997 06 08 16:51  */

#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/uio.h>

void trace();
void InitWorld();

#define FALSE 0
#define TRUE 1

/* ----------------------- */
/* Communicating functions */
/* ----------------------- */

char *Message_Tags[] = {"deny", 
                        "accept" ,
                        "open_auction",
                        "open_round",
                        "good",
                        "buyers",
                        "goods",
                        "offer",
                        "sold",
                        "sanction",
                        "expulsion",
                        "collision",
                        "out_of_market",
                        "end_round",
                        "end_auction",
                        "closed_market"};
      
#define PREDICATES 16                        
                        
#define UNKNOWN       -1
#define DENY           0
#define ACCEPT         1
#define OPEN_AUCTION   2
#define OPEN_ROUND     3
#define GOOD           4
#define BUYERS         5
#define GOODS          6
#define OFFER          7
#define SOLD           8
#define SANCTION       9
#define EXPULSION     10
#define COLLISION     11 
#define OUT_OF_MARKET 12
#define END_ROUND     13
#define END_AUCTION   14
#define CLOSED        15

#define BUFSIZE 4096

#define READY_TO_BID  2112

void  Send(int remote_control, char *string) {
 printf("\n%s\n",string);
 write(remote_control, string, strlen(string));	
}

int Get_Char(int fd) {
 static char buf[BUFSIZE];
 static char *bufp = buf;
 static int n= 0;
 if (n == 0) {
  n = read(fd, buf, sizeof buf);
  bufp = buf;
 }
 return (--n >= 0) ? (unsigned char) *bufp++ : EOF;
}

char *GetWord(int pannel) {
 char Buf[BUFSIZE];
 int i=0;
 static unsigned char c='\0';
 
 if (c=='\n') {
  Buf[i] = c = '\0';
  return(Buf);
 }
 
 c = Get_Char(pannel);
  
 while (isspace(c)) {
  c = Get_Char(pannel);
 }
 
 while (!isspace(c)) {
  Buf[i] = c;
  i++;
  c = Get_Char(pannel); 	
 }

 Buf[i] ='\0';
 printf("%s ",Buf);
 return(Buf);
} 
 

int Receive(int pannel) {
 char Buf[BUFSIZE];
 int i;
 
 strcpy(Buf, GetWord(pannel)); 
	
 for (i=0;i<PREDICATES;i++) {
  if (!strcmp(Buf,Message_Tags[i]))
   return i; 
 } 
  return UNKNOWN; 	
}

long int GetNumericParameter(int pannel) {
 char Buf[BUFSIZE];
 
 strcpy(Buf,GetWord(pannel)); 
 
 return(atol(Buf));
}

char *GetSymbolicParameter(int pannel) {
 char Buf[BUFSIZE];
 
 strcpy(Buf,GetWord(pannel)); 
 	
 return (Buf);	
}	

/* ----------------------- */
/* FishMarket world...     */
/* ----------------------- */

#define FM_Ps 10
#define FM_to 500
#define FM_tr 2000
#define FM_Cmax 3
#define FM_Sf 0.25
#define FM_e  0

#define FM_n 21
#define FM_ta 5000

long int current_auction = 0;
long int round_number    = 0;

#define FM_auction_credit 50000

long int my_credit[FM_n];
long int my_expected_benefit[FM_n];

#define NOGOOD  -1
#define NOPRICE -1
#define NOSOLD  -1

int current_good;
long int current_price;
int I_bid = FALSE;
int I_can_bid = FALSE;

int go_on = TRUE;


/* ----------------------- */
/* Goods                   */
/* ----------------------- */

#define MAX_GOODS 200

struct TGood Goods_to_be_sold[FM_n][MAX_GOODS];

int NGoods_to_be_sold[FM_n];

struct TGood {
 char identifier[16];
 char kind[16];
 char seller[16];
 long int init_price;
 long int retention_price;
 long int resale_price;
 char buyer[16];
 long int price;		
};

long int benefit(struct TGood g) {
 return(g.resale_price - g.price);
}

/* ----------------------- */
/* Buyers                  */
/* ----------------------- */

#define MAX_BUYERS 100

struct TBuyer Buyers[FM_n][MAX_BUYERS];

int NBuyers[FM_n];

#define BUYER_IN 0
#define BUYER_OUT 1
#define BUYER_EXPELLED 2

struct TBuyer {
 char name[32];
 struct TGood goods[MAX_GOODS];
 int Ngoods;
 long int benefit;
 long int expenses;
 int state; 
};

/* ----------------------- */
/* Who am I?               */
/* ----------------------- */

#define MY_LOGIN "jarisco"
#define MY_PASSWORD "jarisco"


int Remote_Control[2];
int Pannel[2];


void InitWorld() {
 int i; 
  
 for (i=0;i<FM_n;i++) {
  my_credit[i] = FM_auction_credit;
  my_expected_benefit[i] = 0;
  NGoods_to_be_sold[i] = 0;
  NBuyers[i] = 0;
 }

}

/* ----------------------- */
/* Messages                */
/* ----------------------- */

void catch_the_remote_control() {
 char *const argv[] = {"Jarisco", MY_LOGIN};	
 pipe(Remote_Control);
 pipe(Pannel);
 if (fork()==0) {
  close(0);
  dup(Remote_Control[0]);
  close(1);
  dup(Pannel[1]);
  close(Remote_Control[0]);
  close(Remote_Control[1]);
  close(Pannel[0]);
  close(Pannel[1]);
  execvp("Jarisco", argv);
  exit();
 }     
 close(Remote_Control[0]);
 close(Pannel[1]); 
 InitWorld();
}	


/* ----------------------- */
/* My Illocutions          */
/* ----------------------- */

void Go_Into_Auction_Room(remote_control) {
 char buffer[256];
 sprintf(buffer, "admission %s %s\n", MY_LOGIN, MY_PASSWORD);
 Send(remote_control, buffer);
}

void Bid(remote_control) {
 char buffer[256];
 sprintf(buffer, "bid\n");
 Send(remote_control, buffer);
}

void Exit_from_the_Market(remote_control) {
 char buffer[256];
 sprintf(buffer, "exit\n");
 Send(remote_control, buffer);
}

/* ----------------------- */
/* Buyer actions           */
/* ----------------------- */

void get_deny_code(int pannel) {
 printf("\n Access denied: %s\n", GetSymbolicParameter(pannel));  	
}

void get_auction_number(int pannel) {
 current_auction = GetNumericParameter(pannel)-1;	
 NGoods_to_be_sold[current_auction] = 0;
 NBuyers[current_auction] = 0;
 my_credit[current_auction]= FM_auction_credit;
 my_expected_benefit[current_auction] = 0;
 current_good = NOGOOD;
 current_price = NOPRICE;
 I_bid = FALSE;
 go_on = TRUE;
}

void get_auction_closed_number (int pannel) {
 GetNumericParameter(pannel);
 current_good = NOGOOD;
 current_price = NOPRICE;
 I_bid = FALSE;
 go_on = FALSE;
}

void get_round_number(int pannel) {
 round_number =	GetNumericParameter(pannel)-1;
 current_good = NOGOOD;
 current_price = NOPRICE;
 I_bid = FALSE;
 I_can_bid = FALSE;
}

void get_round_closed_number(int pannel) {
 GetNumericParameter(pannel);
 current_good = NOGOOD;
 current_price = NOPRICE;
}

void get_good_info (int pannel) {
 char identifier[16];
 int i, found = FALSE;
 strcpy(identifier,GetSymbolicParameter(pannel));
 for (i=0;i<NGoods_to_be_sold[current_auction] && !found; i++) {
   if (!strcmp(identifier,Goods_to_be_sold[current_auction][i].identifier)) {
    found = TRUE;
    current_good = i;
   }
 }
 GetSymbolicParameter(pannel);
 GetSymbolicParameter(pannel);
 GetNumericParameter(pannel);
 GetNumericParameter(pannel);
 current_price = Goods_to_be_sold[current_auction][current_good].init_price;
}

void update_list_buyers(int pannel) {
 char buyer_name[16];
 int i, found; 

 for (i=0;i<NBuyers[current_auction];i++) {
  Buyers[current_auction][i].state = BUYER_OUT;
 }

 strcpy(buyer_name,GetSymbolicParameter(pannel));  

 while (buyer_name[0]!='\0') { 
  found = FALSE;
  for (i=0;i<NBuyers[current_auction] && !found;i++) {
    if (!strcmp(buyer_name,Buyers[current_auction][i].name)) {
     found = TRUE;
     Buyers[current_auction][i].state = BUYER_IN;
    }
  }
  if (!found) {
   strcpy(Buyers[current_auction][NBuyers[current_auction]].name,buyer_name);
   Buyers[current_auction][NBuyers[current_auction]].Ngoods = 0;
   Buyers[current_auction][NBuyers[current_auction]].benefit = 0;
   Buyers[current_auction][NBuyers[current_auction]].expenses = 0;
   Buyers[current_auction][NBuyers[current_auction]].state = BUYER_IN;
   NBuyers[current_auction]++;
  }  
  strcpy(buyer_name,GetSymbolicParameter(pannel));  
 }	
}

void update_list_goods(int pannel) {
 char identifier[16];
 strcpy(identifier, GetSymbolicParameter(pannel));
 while (identifier[0]!='\0') {
  strcpy(Goods_to_be_sold[current_auction][NGoods_to_be_sold[current_auction]].identifier,
         identifier                  );
  strcpy(Goods_to_be_sold[current_auction][NGoods_to_be_sold[current_auction]].kind,
         GetSymbolicParameter(pannel));
  strcpy(Goods_to_be_sold[current_auction][NGoods_to_be_sold[current_auction]].seller,
         GetSymbolicParameter(pannel));
  Goods_to_be_sold[current_auction][NGoods_to_be_sold[current_auction]].init_price = 
         GetNumericParameter(pannel);
  Goods_to_be_sold[current_auction][NGoods_to_be_sold[current_auction]].retention_price;
  
  Goods_to_be_sold[current_auction][NGoods_to_be_sold[current_auction]].resale_price = 
         GetNumericParameter(pannel);
   
  NGoods_to_be_sold[current_auction]++;
  strcpy(identifier, GetSymbolicParameter(pannel));
 }        	
}

void get_price_info(int pannel) {
 GetSymbolicParameter(pannel);
 current_price = GetNumericParameter(pannel);
 I_can_bid = TRUE;	
}

void get_sale_info(int pannel) {
 char buyer_name[16];
 long int price;
 int i,found;

 strcpy(buyer_name, GetSymbolicParameter(pannel));
 price = GetNumericParameter(pannel);
 strcpy(Goods_to_be_sold[current_auction][current_good].buyer,buyer_name);
 Goods_to_be_sold[current_auction][current_good].price = price;
 
 found = FALSE;
 for (i=0;i<NBuyers[current_auction] && !found; i++) {
   if (!strcmp(buyer_name,Buyers[current_auction][i].name)) {
    found = TRUE;
    Buyers[current_auction][i].benefit += benefit(Goods_to_be_sold[current_auction][current_good]);
    Buyers[current_auction][i].expenses += price;
   }
 }
 
 if (I_bid && !strcmp(buyer_name,MY_LOGIN)) {
  my_credit[current_auction] -= price;
  my_expected_benefit[current_auction] += benefit(Goods_to_be_sold[current_auction][current_good]); 
 }	
 
 I_bid = FALSE;

 current_good = NOGOOD;
 current_price = NOPRICE; 

}

void get_sanction_info(int pannel) {
 char buyer_name[16];
 long int price;
 int i,found;

 strcpy(buyer_name, GetSymbolicParameter(pannel));
 price = GetNumericParameter(pannel);

 found = FALSE;
 for (i=0;i<NBuyers[current_auction] && !found; i++) {
   if (!strcmp(buyer_name,Buyers[current_auction][i].name)) {
    found = TRUE;
    Buyers[current_auction][i].expenses += price;
   }
 }
}

void get_expelled_buyer(int pannel) {
 char buyer_name[16];
 int i,found;

 strcpy(buyer_name, GetSymbolicParameter(pannel));

 found = FALSE;
 for (i=0;i<NBuyers[current_auction] && !found; i++) {
   if (!strcmp(buyer_name,Buyers[current_auction][i].name)) {
    found = TRUE;
    Buyers[current_auction][i].state = BUYER_EXPELLED;
   }
 }	
}


void get_collision_price(int pannel) {
 I_bid = FALSE;
 get_price_info(pannel);	
}

void get_not_sold_good(int pannel) {
 GetSymbolicParameter(pannel);
 Goods_to_be_sold[current_auction][current_good].price = NOSOLD;
 Goods_to_be_sold[current_auction][current_good].retention_price = 
  GetNumericParameter(pannel);
 current_good = NOGOOD;
 current_price = NOPRICE;
}

void close_the_auction() {
 go_on = FALSE;
}


/* -------------------------- */
/* Remote Control Illocutions */
/* -------------------------- */

int get_message(int pannel) {
 int message;

 printf("\n\n"); 

 message = Receive(pannel);
 
 switch (message) {
 case DENY:   get_deny_code(pannel);
               break;	
  case ACCEPT: return(READY_TO_BID);  
               break;       
  case OPEN_AUCTION:
  	       get_auction_number(pannel);
  	       break;
  case OPEN_ROUND:
               get_round_number(pannel);
               trace();
               break;
  case GOOD:   get_good_info(pannel);
               break;
  case BUYERS: update_list_buyers(pannel);
               break;
  case GOODS:  update_list_goods(pannel);
               break;
  case OFFER:  get_price_info(pannel);
               break;
  case SOLD:   get_sale_info(pannel);
               break;
  case SANCTION: 
               get_sanction_info(pannel);
               break;
  case EXPULSION:
               get_expelled_buyer(pannel);
               break;
  case COLLISION:
               get_collision_price(pannel);
               break;
  case OUT_OF_MARKET:
               get_not_sold_good(pannel);
               break;
  case END_ROUND:
               get_round_closed_number(pannel);
               break;
  case END_AUCTION:
               get_auction_closed_number(pannel);
               break;
  case CLOSED: close_the_auction();
               break;
 }   
 return(UNKNOWN);
 
}

/* ----------------------- */
/* Strategy                */
/* ----------------------- */

void  To_Bid_or_Not_to_Bid(remote_control) {
 if (current_good != NOGOOD && current_price != NOPRICE &&
     current_price < my_credit[current_auction] &&
     current_price < Goods_to_be_sold[current_auction][current_good].resale_price && 
     I_can_bid &&
     (rand() & 01)) { 
   Bid(remote_control);
   I_bid = TRUE; 	
  }
 I_can_bid = FALSE; 	
}

/* ----------------------- */
/* Buyer                   */
/* ----------------------- */

main(int argc,char *argv[]) {
 catch_the_remote_control();
 Go_Into_Auction_Room(Remote_Control[1]); 
 while (current_auction < FM_n) {
  go_on = TRUE;
 /* Go_Into_Auction_Room(Remote_Control[1]); */
  while (go_on) {
   get_message(Pannel[0]);
   To_Bid_or_Not_to_Bid(Remote_Control[1]);
  } 	   	
 } 			
}


void printGood(struct TGood g) {
 printf("\n id: %s ki: %s se: %s ip: %d rt: %d rs: %d bu: %s pi: %d\n",
        g.identifier, g.kind, g.seller, g.init_price, g.retention_price,
        g.resale_price, g.buyer, g.price); 
}

void printBuyer(struct TBuyer b) {
 int i;
 printf("\n na: %s be: %d ex: %d\n", b.name, b.benefit, b.expenses);
 
 for (i=0; i<b.Ngoods; i++) {
  printf(" %s ",b.goods[i].identifier); 
 }

 printf("\n-------------------------------------------\n");

} 


void trace() {
 int i,j;

 for (i=0;i<FM_n;i++) {
  printf("\n--------------------\n");
  printf("Credit: %d\n Benefit: %d \n", my_credit[i], my_expected_benefit[i]);
 }
 
 for (i=0;i<FM_n;i++) {
   printf("------GOODS-------\n");
   for (j=0;j<NGoods_to_be_sold[i];j++) {
    printGood(Goods_to_be_sold[i][j]);
   }
   printf("------BUYERS-------\n");
   for (j=0;j<NBuyers[i];j++) {
    printBuyer(Buyers[i][j]);    
   }
 }

}



