package body dispatchers is

    task body Dispatcher is
        HANDLERS_COUNT                 : constant Integer  := 2;
        MAX_SOCKETS_COUNT              : constant Integer  := 1000;
        UNDISPATCHED_SOCKET_RETRY_TIME : constant Duration := 0.5;

        handlers : array (1 .. HANDLERS_COUNT) of Handler;

        type Socket_Index is range 1..MAX_SOCKETS_COUNT;
        package Socket_Vector is new Ada.Containers.Vectors (
            Element_Type => Socket_Type,
            Index_Type   => Socket_Index);

        function Find_Free_Handler(s: Socket_Type) return Boolean is
        begin
            for id in handlers'Range loop
                select
                    handlers(id).handle(s);
                    return True;
                else
                    null;
                end select;
            end loop;
            return False;
        end Find_Free_Handler;

        result : Boolean;
        undispatched : Socket_Vector.Vector;

    begin
        accept start;

        for id in handlers'Range loop
            handlers(id).start(id);
        end loop;

        loop
            select
                accept dispatch (s: Socket_Type) do
                    Put_Line ("dispatch command");
                    result := Find_Free_Handler(s);
                    if not result then
                        Put_Line("All handlers are busy");
                        undispatched.Append(s);
                    end if;
                end dispatch;
            or
                accept stop do
                    Put_Line("stop command, stopping dispatcher");
                end stop;
                exit;
            or
                delay UNDISPATCHED_SOCKET_RETRY_TIME;
                if Integer(undispatched.Length) > 0 then
                    declare
                        s: Socket_Type := undispatched.Element(1);
                    begin
                        result := Find_Free_Handler(s);
                        if result then
                            undispatched.Delete(1);
                            Put_Line("Handled undispatched client");
                        end if;
                    end;
                end if;
            end select;
        end loop;

        for id in handlers'Range loop
            handlers(id).stop;
        end loop;


    end dispatcher;
end dispatchers;