// SPDX-License-Identifier: MIT
// Copyright (c) 2026 Incoprea
// Find the first gap long enough for a cue
// Not compiled or tested in-world
// Setup: Place in a spare owned prim. Set reservation start/end pairs, EARLIEST and positive DURATION. Owner touch runs a bounded local calculation.
// Stop / restore: Disable/remove. No travel, publication, payments or external operations occur.
// Notes: Reservations may overlap; sorting and advancing the candidate handles their union without modifying them.
// License: see LICENSE in this distribution.
// Original Incoprea. MIT. Local planning demonstration.
list BUSY=[2.0,4.0,5.0,6.0,8.0,10.0];
float EARLIEST=1.0;
float DURATION=2.0;
default
{
    touch_start(integer detectedCount)
    {
        if(llDetectedKey(0)!=llGetOwner())return;
        if(DURATION<=0.0||llGetListLength(BUSY)%2)
        {
            llOwnerSay("Invalid intervals/duration.");
            return;
        }
        integer i;
        for(i=0;i<llGetListLength(BUSY);i+=2)if(llList2Float(BUSY,i+1)<llList2Float(BUSY,i))
        {
            llOwnerSay("Invalid reservation.");
            return;
        }
        list sorted=llListSort(BUSY,2,TRUE);
        float candidate=EARLIEST;
        for(i=0;i<llGetListLength(sorted);i+=2)
        {
            float start=llList2Float(sorted,i);
            float end=llList2Float(sorted,i+1);
            if(candidate+DURATION<=start)
            {
                llOwnerSay("Free slot="+(string)candidate+".."+(string)(candidate+DURATION));
                return;
            }
            if(candidate<end)candidate=end;
        }
        llOwnerSay("Free slot="+(string)candidate+".."+(string)(candidate+DURATION));
    }
}
