classdef Sock < handle
    % Mechlab : SocketObject Matej Rajchl <matej.rajchl@mechlab.cz>
    % modificattion by Tomas Pospichal 
    %   - Java DataOutputStream function write => input as uint8
    %   - added read pooling (allowing timeout)
    %   - removed closing of stream after each write
    %   - observable properties
    properties %(Access = private)
        Host
        Port
        Handle
        com        
        lengthBuffer=512;
    end
    
    properties (SetObservable = true)
        isopen = false;
    end
    
    methods
        function obj = Sock(host,port)
            if nargin > 1
                obj.Host = host;
                obj.Port = port;
            end
        end
        
        function status = open(obj)
            import java.net.Socket
            number_of_retries = 5; % set to -1 for infinite
            
            retry        = 0;
            input_socket = [];
            
            
            fprintf(1, 'Connecting to %s:%d\n', obj.Host, obj.Port);
                    
            while true
                
                retry = retry + 1;
                if ((number_of_retries > 0) && (retry > number_of_retries))
                    error('Too many retries');
                    status = 1;
                    return;
                end
                
                try
                    % throws if unable to connect
                    input_socket = Socket(obj.Host, obj.Port);

%                     input_socket.setSoTimeout(5)
                    
                    fprintf(1, 'Connected to server\n');
                    break
                    
                catch
                    if ~isempty(input_socket)
                        input_socket.close;
                    end
                    
                    fprintf(1, 'Connection attempt failed, retrying...\n');
                       
                    % pause before retrying
                    pause(1);
                end
            end
        obj.isopen = true;
        obj.com = input_socket;
        status = 0;
        end
        
        function status = close(obj)
            import java.net.Socket
             try
                %obj.com.ShutdownInput()
                %obj.com.ShutdownOutput()
                obj.com.close();
                obj.isopen = false;
                status = 0;
             catch
                status = 1;
                obj.com.close()
                error('An error while closing the socket occured');
             end        
        end
        
        function status = send(obj, data)
            % expects data in uint8 format
            import java.io.*
            try
 
                output_stream   = obj.com.getOutputStream;

                d_output_stream = DataOutputStream(output_stream);

                %d_output_stream.writeBytes(char(data));
                d_output_stream.write(data);

                d_output_stream.flush;   
                %d_output_stream.close;
                status = 0;
            catch
                obj.com.close()
                error('An error occured while sending data to DataOutputStream')
                status = 1;
            end
        end
        
        function DataAvailable = poolRead(obj)
            import java.io.*
            try
                 input_stream = obj.com.getInputStream;
                 DataAvailable = input_stream.available();
            catch MS
                disp(MS)
            end
        end
        function [data] = read(obj,n_bytes)
            import java.io.*
  
            try    
                input_stream = obj.com.getInputStream;
                d_input_stream = DataInputStream(input_stream);
                n_bytes=min(n_bytes,obj.lengthBuffer);
                data = zeros(1, n_bytes, 'uint8');
                for i = 1:n_bytes
%                     new_byte = d_input_stream.readByte();
                    data(i) = d_input_stream.readUnsignedByte();
                end
            catch MS
                disp(MS)
                obj.com.close()
                error('An error occured while reading data from DataInputStream')
                status = 1;
            end
        end
        function status = delete(obj)
            obj.com.close()
            %system('taskkill /F /IM FTDIwrapper.exe')
        end
    end
end