package upem.net.tcp.nonblocking.chat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Optional;
import java.util.Scanner;


public class ClientChat {

    private static Charset UTF8 = Charset.forName("UTF-8");


    private static boolean readFully(ByteBuffer bb,SocketChannel sc) throws IOException {
        while(bb.hasRemaining()){
            if (sc.read(bb)==-1) return false;
        }
        return true;
    }

    private  static Optional<Integer> readInt(SocketChannel sc) throws IOException {
        ByteBuffer buff = ByteBuffer.allocate(Integer.BYTES);
        if (!readFully(buff,sc)) return Optional.empty();
        buff.flip();
        return Optional.of(buff.getInt());
    }
    private  static void writeInt(int i,SocketChannel sc) throws IOException, InterruptedException {
        ByteBuffer buff = ByteBuffer.allocate(Integer.BYTES);
        buff.putInt(i);
        buff.flip();
        sc.write(buff);
    }

    private static void writeString(String output, SocketChannel sc) throws IOException, InterruptedException {
        ByteBuffer content = UTF8.encode(output);
        writeInt(content.remaining(), sc);
        sc.write(content);
    }

    private static Optional<String> readString(SocketChannel sc) throws IOException {
        Optional<Integer> size = readInt(sc);
        if (!size.isPresent()) return Optional.empty();
        ByteBuffer bb = ByteBuffer.allocate(size.get());
        if (!readFully(bb,sc)) return Optional.empty();
        bb.flip();
        return Optional.of(UTF8.decode(bb).toString());
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        if (args.length!=3) {
            System.out.println("ClientChat login hostname port");
            return;
        }
        SocketChannel sc = SocketChannel.open();
        sc.connect(new InetSocketAddress(args[1],Integer.valueOf(args[2])));
        String login = args[0];
    
        new Thread(() -> {
            try {
                Scanner scan = new Scanner(System.in);
                while(scan.hasNextLine()){
                    String txt = scan.nextLine();
                    writeString(login, sc);
                    writeString(txt,sc);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();


        for (; ; ) {
            Optional<String> log = readString(sc);
            if (!log.isPresent()) {
                System.out.println("Protocol error");
                return;
            }
            Optional<String> txt = readString(sc);
            if (!txt.isPresent()) {
                System.out.println("Protocol error");
                return;
            }
            System.out.println(log.get() + " : " + txt.get());
        }
    }
}
