package electrosphere.net.parser.net.raw;

import electrosphere.net.parser.net.message.NetworkMessage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class NetworkParser {
    
    InputStream incomingStream;
    OutputStream outgoingStream;
    
    CopyOnWriteArrayList<NetworkMessage> incomingMessageQueue = new CopyOnWriteArrayList<NetworkMessage>();
    CopyOnWriteArrayList<NetworkMessage> outgoingMessageQueue = new CopyOnWriteArrayList<NetworkMessage>();
    
    CircularByteBuffer incomingByteBuffer = new CircularByteBuffer(64 * 1024 * 124);
    CopyOnWriteArrayList<Byte> outgoingByteQueue = new CopyOnWriteArrayList<Byte>();
    
    
    
    public NetworkParser(InputStream incomingStream, OutputStream outgoingStream){
        this.incomingStream = incomingStream;
        this.outgoingStream = outgoingStream;
    }
    
    public void start(){
        
    }
    
    static final int READ_BUFFER_SIZE = 64 * 1024 * 1024;
    byte[] readBuffer = new byte[READ_BUFFER_SIZE];
    public void readMessagesIn(){
        try {
            //read in bytes
            int bytesRead = 0;
            byte currentByte = -1;
            while(incomingStream.available() > 0){
                // nextValue = incomingStream.read();
                bytesRead = incomingStream.read(readBuffer, 0, READ_BUFFER_SIZE);
                if(bytesRead > 0){
                    incomingByteBuffer.add(readBuffer, bytesRead);
                }
            }
            //parse byte queue for messages
            //for each message, append to clientIncomingMessageQueue
            NetworkMessage newMessage;
            while((newMessage = NetworkMessage.parseBytestreamForMessage(incomingByteBuffer))!=null){
                incomingMessageQueue.add(newMessage);
            }
        } catch (IOException ex) {
            ex.printStackTrace();
            System.exit(0);
        }
    }
    
    public void pushMessagesOut(){
        for(NetworkMessage message : outgoingMessageQueue){
            outgoingMessageQueue.remove(message);
            try {
//                System.out.println("Write message of type " + message.getType());
                outgoingStream.write(message.getRawBytes());
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
    
    public boolean hasIncomingMessaage(){
        return incomingMessageQueue.size() > 0;
    }
    
    public NetworkMessage popIncomingMessage(){
        return incomingMessageQueue.remove(0);
    }
    
    public void addOutgoingMessage(NetworkMessage message){
        outgoingMessageQueue.add(message);
    }

    /**
     * Copies the current contents of the incoming messages queue to a provided list
     * @param messages The list to copy the incoming messages to
     */
    public void copyIncomingMessages(List<NetworkMessage> messages){
        messages.addAll(incomingMessageQueue);
    }

    /**
     * Copies the current contents of the outgoing messages queue to a provided list
     * @param messages The list to copy the outgoing messages to
     */
    public void copyOutgoingMessages(List<NetworkMessage> messages){
        messages.addAll(outgoingMessageQueue);
    }
    
}
