// Auction Server

import java.io.*;
import java.util.*;
import java.net.*;

public class AuctServer extends Thread
  {
  static String ulist;

  Socket csock;                // the socket
  static Calendar endtime;     // end time of auction
  static float highbid=0.0f;   // high bid
  static String bidder;        // high bidder
  static boolean done=false;   // finished?
  static String pfn;           // property file name
  static Properties p;         // property database

  public AuctServer(Socket skt) { csock=skt; }

// handle a bid
  synchronized private void bid(String bidid, float bidamt)
  // synchronized
    {
      Calendar cal=Calendar.getInstance();
      long diff;
      System.out.println(bidid + " bids " + bidamt);
    // check for time
      if (cal.after(endtime)) return;  // too late
    // check for bid amount
      if (highbid>=bidamt) return;
    // if all OK set high bid
      System.out.println("High bid: " + bidid + " = " + bidamt);
      highbid=bidamt;
      bidder=bidid;
    //   and adjust time if <60 seconds left
      diff=(endtime.getTime().getTime()-cal.getTime().getTime())/1000;
      if (diff<60) endtime.add(Calendar.SECOND,60);
      // add 1 more minute
    }  

// generate status
  synchronized private void status(PrintWriter pw)
    {
      Calendar cal=Calendar.getInstance();
      long diff;
      // check time
      diff=(endtime.getTime().getTime()-cal.getTime().getTime())/1000;
      if (diff<=0 && !done)
        {  // if first time we've noticed we are done, complete auction
      done=true;
      p.put("HighBid",Float.toString(highbid));
      p.put("HighBidder",bidder);
          System.out.println("Auction complete "+ bidder
              + " " + highbid);
      try 
       {
        p.store(new FileOutputStream(pfn),""); 
         // p.save is deprecated!
       } catch (Exception e)
         {
         System.out.println("Error ending auction");
         System.out.println(e.getMessage());
         e.printStackTrace(System.out);
         }
     }
      if (diff<0) diff=0;   // don't return negative time
      pw.print(diff);
      pw.print(":");
      pw.print(highbid);
      pw.print(":");
      pw.print(bidder);
      pw.print("\n");
      pw.flush();
    }

// each client thread runs this code
  public void run()
    {
    String cmd;
    try
      {
      InputStream istream = csock.getInputStream();
      PrintWriter pw = new PrintWriter(csock.getOutputStream());

      OutputStream ostream = csock.getOutputStream();
      BufferedReader br = new
          BufferedReader(new InputStreamReader(istream));
// read commands
      while (true) {
        cmd=br.readLine();
        if (cmd==null) break;    // connection dropped?
        if (cmd.charAt(0)=='S')  // status command
          {
          status(pw);
          }
        if (cmd.charAt(0)=='B')  // bid
          {
         String id;
         float amt;
         int n;
         n=cmd.indexOf(':');
         id=cmd.substring(1,n);
         amt=Float.valueOf(cmd.substring(n+1)).floatValue();
         bid(id,amt); // parse these out
          status(pw);
          }
        }
      } catch (Exception e) { }    
    }

// This is the server's main entry point
  public static void main(String args[]) throws Exception
    {
    ServerSocket sock;
    p=new Properties();
    pfn="auction" + args[0] + ".properties";
    p.load(new FileInputStream(pfn));   // read database

  // compute end time
    endtime=Calendar.getInstance();
    endtime.add(Calendar.MINUTE,
         Integer.parseInt(p.getProperty("EndAt")));

  // create server socket
    sock=new ServerSocket(Integer.parseInt(p.getProperty("port")));

  // accept connections from clients
    while (true) {
      new AuctServer(sock.accept()).start();
      }
    }
  }
