{
// file launcher.jsx
//
// dvb2005.04.02 -- Build a palette containing all the scripts in specified
// folders. This makes it easier to launch 'em.
// Includes also the ability to a) rescan all folders, and b) drop into debugger
// just before executing.


// +----------------------------------
// | Modify this folder list to your liking!
// |

var gFolderPaths =
        [
//        "./",
        "./Scripts/",
        "/Users/poly/src/after_effects_scripts/"
        ];


var gLibraries; // global array of *Lib.jsx files, built when we scan folders
var gCurrentScriptFile;  // while executing

function endsWith(aString,ending)
    {
    var endingLength = ending.length;
    var aStringLength = aString.length;
    var maybeEnding = aString.substring(aStringLength - endingLength,aStringLength);
    var result = (ending == maybeEnding);
    return result;
    }

// rectangles are [0..3] [left,top,right,bottom]
function bumpBounds(bounds,y)
    {
    var h = bounds[3] - bounds[1];
    var bump = h + y;

    bounds[1] += bump;
    bounds[3] += bump;
    }

// given a rectangle [left,top,right,bottom]
// return a partial column from it
function getPartialBounds(bounds,index,columns)
{
    var result = copyBounds(bounds);
    var left = bounds[0];
    var right = bounds[2];
    var width = right - left;
    result[0] = left + width * index / columns;
    result[2] = left + width * (index + 1) / columns;

    return result;
}

function sayBounds(bounds)
{
    var s = "(";
    s += bounds[0] + "," + bounds[1] + "," + bounds[2] + "," + bounds[3];
    s += ")";
    return s;
}

function copyBounds(bounds)
    {
    var result = new Array();

    for(i = 0; i < 4; i++)
        result[i] = bounds[i];

    return result;
    }

function doInfoButtonClick()
{
    var s;

    s = "Script Directories:\n";
    for(i = 0; i < gFolderPaths.length; i++)
    {
        var aPath = gFolderPaths[i];
        s += "   " + aPath + "\n";
    }

    alert(s);
}

function doScriptButtonClick()
    {
    var theButton = this;
    var doDebug = theButton.debugWidget.value;

    if(0)
        alert(theButton.theScriptName + " clicked.\n"
                + "debug = " + doDebug + ".\n"
                + "path = " + theButton.theScriptFile.fsName + ".\n"
                );

    var theScriptFile = theButton.theScriptFile;
	var oldCurrentFolder = Folder.current;
	Folder.current = theScriptFile.parent;

	theScriptFile.open();
    var theScriptContents = theScriptFile.read();
	theScriptFile.close();

    gCurrentScriptFile = theScriptFile;

    if(doDebug)
        debugger;

    // You have entered the debugger in Launcher...
    // to debug the script you've launched, step
    // into the eval() function below. 
    //
    // IF your script has certain kinds of syntax
    // errors such as mimatched braces,
    // THEN stepping-in will fail!
    //
    // Thanks for using Launcher.
    // -- David Van Brink, poly@omino.com, 2005

    eval( "{" + theScriptContents + "}" );

	Folder.current = oldCurrentFolder;
    gCurrentScriptFile = "";
    }

function buildPalette(paletteLeft,paletteTop)
    {
    Folder.current = primordialDirectory;  // always same starting point...

    var thePalette = new Window("palette","Launcher");

    var bounds = [10,10,180,24];

    thePalette.add('statictext',bounds,"Launcher, by poly@omino.com 2005-7");
    bumpBounds(bounds,5);
    thePalette.rescanWidget = thePalette.add('button',bounds,"Rescan Folders");

    // clever but lame way to make rescan rework the whole dialog.
    thePalette.rescanWidget.onClick = function(){this.parent.relaunch = true;this.parent.hide();};

    bumpBounds(bounds,12);
    debugBounds = getPartialBounds(bounds,0,2);
    thePalette.debugWidget = thePalette.add('checkbox',debugBounds,"Debug");
    infoBounds = getPartialBounds(bounds,5,6);
    thePalette.infoWidget = thePalette.add('button',infoBounds,"?");
    thePalette.infoWidget.onClick = doInfoButtonClick;


    // now, scan them folders
    var folderPaths = new Array();

    // get the main list from gFolderLists
    var i;
    for(i = 0; i < gFolderPaths.length; i++)
        folderPaths[folderPaths.length] = gFolderPaths[i];

    // augment with project and project/scripts current folders

    var project = app.project;
    if(project != null)  // at startup, project is null
        {
        var projectFile = app.project.file;
        if(projectFile != null)
            {
            var projectFolder = projectFile.parent;
            var projectFolderPath = projectFolder.fsName;

            folderPaths[folderPaths.length] = projectFolderPath;
            folderPaths[folderPaths.length] = projectFolderPath + "/scripts";
            }
        }

    var scriptCount = 0;
    var scriptButtons = new Array();
    gLibraries = new Array();
    for(i = 0; i < folderPaths.length; i++)
        {
        var aFolderPath = folderPaths[i];
        var aFolder = new Folder(aFolderPath);
        var scripts = aFolder.getFiles("*.jsx");

        if(scripts.length > 0)
            bumpBounds(bounds,3); // little extra gap for each group

        var j;
        for(j = 0; j < scripts.length; j++)
            {
            var aScriptFile = scripts[j];
            var aScriptName = aScriptFile.name;

            // stash libraries (...Lib.jsx) into array
            // for later retrieval. The our routine "loadLibrary"
            // finds it by name.

            if(endsWith(aScriptName,"Lib.jsx"))
                {
                gLibraries[gLibraries.length] = aScriptFile;
                }
            else
                {
                // make a button for it, too.
                bumpBounds(bounds,5);
                var aButton = thePalette.add('button',bounds,aScriptName);
                aButton.theScriptFile = aScriptFile;
                aButton.theScriptName = aScriptName;
                aButton.onClick = doScriptButtonClick;
                aButton.debugWidget = thePalette.debugWidget;

                scriptButtons[scriptCount++] = aButton;
                }
            } // for j
        } // for i

    thePalette.scriptButtons = scriptButtons;

    var paletteBounds = copyBounds(bounds);
    paletteBounds[0] = paletteLeft;
    paletteBounds[1] = paletteTop;
    paletteBounds[2] += paletteLeft + 10;
    paletteBounds[3] += paletteTop + 10;
    thePalette.bounds = paletteBounds;

    thePalette.relaunch = false;
    thePalette.onClose = paletteCloseAction;

    var resultCode = thePalette.show();

    return resultCode;
    }

function paletteCloseAction()
    {
    var thePalette = this;

    // kind of lame; each time you hit rescan you burn up
    // more memory. But functionally works ok. but lame. dvb05

    if(thePalette.relaunch)
        buildPalette(thePalette.bounds[0],thePalette.bounds[1]); // retain position, too
    }
    
// Load and return library contents, by name
// we'll try to use the one locally but use any otherwise
function loadLibrary(libraryName)
    {
    var i;
    var fileLocal = "";
    var fileAny = "";
    var libraryList = "";
    for(i = 0; i < gLibraries.length; i++)
        {
        var aLibraryFile = gLibraries[i];

        libraryList += "\n" + aLibraryFile.name; // for alert

        if(libraryName == aLibraryFile.name)
            {
            fileAny = aLibraryFile;
            if(aLibraryFile.path == gCurrentScriptFile.path)
                fileLocal = aLibraryFile;
            }
        }

    var foundLibrary = fileAny;
    if(fileLocal != "")
        foundLibrary = fileLocal;

    var theLibraryContents = "";
    if(foundLibrary != "")
        {
        foundLibrary.open();
        theLibraryContents = foundLibrary.read();
        foundLibrary.close();
        }
    else
        {
        alert("Unable to load library: " + libraryName + ".\n"
                + "Known libraries: "
                + libraryList);
        }

    return theLibraryContents;
    }

function main()
    {
    buildPalette(0,300);
    }

// +------------------------------
// | Start Here
// |

var primordialDirectory = Folder.current; // remember this from the initial launch.
main();

}
// end of file
