/*
    starter file for the BLAST client, java version
*/
import java.lang.*;     //pld
import java.net.*;      //pld
import java.io.*;
//import java.io.Externalizable;

public class bclient {

    // The following is useful if you run this from a dynamic console.
    // But don't do that.
    static public void winwait() {
        byte ch[] = new byte[1];
        try {
            System.in.read(ch);
        } catch (IOException ioe) {
            return;
        }
    }

    static blastpkt bp = new blastpkt();    // stupid inner-class nonsense

    //============================================================
    //============================================================

    static public void main(String args[]) {
		String USAGE = "bclient messagenum host port";
		int mesgnum = 0;
        int destport = blastpkt.SERVERPORT;
        String desthost = "ulam.math.luc.edu";

        if (args.length > 1)
        	mesgnum = (new Integer(args[1])).intValue();
       	if (args.length >2)
       	    desthost = args[2];
       	if (args.length > 3)
       	    destport = (new Integer(args[3])).intValue();
       	if (args.length > 4) {
			System.err.println(USAGE);
			return;
		}

        DatagramSocket s;
        try {
            s = new DatagramSocket();
        }
        catch (SocketException se) {
            System.err.println("no socket available");
            return;
        }

        try {
            s.setSoTimeout(blastpkt.DONE);       // time in milliseconds
        } catch (SocketException se) {
            System.err.println("socket exception: timeout not set!");
        }

        InetAddress dest;
        System.err.print("Looking up address of " + desthost + "...");
        try {
            dest = InetAddress.getByName(desthost);
        }
        catch (UnknownHostException uhe) {
            System.err.println("unknown host: " + desthost);
            return;
        }
        System.err.println(" got it!");

        blastpkt.request req = bp.new request(mesgnum); // ctor for REQ

        System.err.println("req size = " + req.size() + "; message number = " + mesgnum);

        DatagramPacket reqDG
            = new DatagramPacket(req.write(), req.size(), dest, destport);

        try {s.send(reqDG);}
        catch (IOException ioe) {
            System.err.println("send() failed");
            return;
        }

        //============================================================

        // now receive the response
		blastpkt.data  bdata = bp.new data();		// blastpkt.data format

        DatagramPacket blastDG            // DatagramPacket format
            = new DatagramPacket(new byte[blastpkt.MAXSIZE] , blastpkt.MAXSIZE);
        DatagramPacket ssrDG
            = new DatagramPacket(new byte[blastpkt.BHEADSIZE], blastpkt.BHEADSIZE);

        long starttime = System.currentTimeMillis();

		try {
			s.receive(blastDG);
		}
		catch (InterruptedIOException iioe) {
			System.err.println("Response timed out!");
			return;
		}
		catch (IOException ioe) {
			System.err.println("receive() failed");
			return;
		}

		//byte[] replybuf = blastDG.getData();	// the actual packet rec'd in byte[] format

		bdata.read(blastDG.getData(), blastDG.getLength());	// now transfer into blastpkt format

		System.err.print("received packet of length = " + blastDG.getLength());
		System.err.print("; port =");
		System.err.print(blastDG.getPort());
		System.err.print("; host=");
		System.err.print(blastDG.getAddress().toString());
		System.err.print("; time = ");
		System.err.print(System.currentTimeMillis()-starttime);
		System.err.print("; data size = ");
		System.err.print(bdata.Data().length);
		System.err.print("; fragment position = " + blastpkt.fragpos(bdata.FragMask()));
		System.err.println();

		// we *should* do some sanity checks on the packet just received!!

		if (mesgnum == 0) {
			byte[] data = bdata.Data();
			int msgcount = (data[0]<<24) + (data[1]<<16) + (data[2]<<8) + data[3];  // lazy convert
			System.err.println("Message 0 indicates there are " + msgcount + " more messages");
	    }

		// now send SSR. If mesgnum == 0, we don't have to wait for more frags
		if (mesgnum == 0) {
            blastpkt.ssr ssr = bp.new ssr(
				bdata.ProtNum(),
				bdata.MID(),
				blastpkt.BHEADSIZE,		// Length
				(short) 1,				// NumFrags
				blastpkt.TYPE_SSR,
				blastpkt.maskmaker(1)	// mask for a single data packet
			); // ctor for REQ

			ssrDG.setAddress(dest);
			ssrDG.setPort(blastDG.getPort());
			ssrDG.setData(ssr.write());
			ssrDG.setLength(ssr.size());

			try {s.send(ssrDG);}
			catch (IOException ioe) {
				System.err.println("ssr send() failed");
				return;
			}
		}

        //============================================================

        //winwait();
    }
}
