/**
 * generate_inner_shadow_dataset.jsx
 *
 * Purpose:
 *   Generate a systematic Inner Shadow effect dataset in Adobe Photoshop.
 *
 * Logic & Workflow:
 *   1. Creates a new transparent RGB document.
 *   2. Adds a raster layer and fills a centered rectangle with black.
 *   3. Applies one Inner Shadow effect via Photoshop ActionDescriptor.
 *   4. Saves the result as a transparent PNG.
 *
 * Arguments:
 *   None (interactive). The user selects an output folder via dialog.
 *
 * Side Effects:
 *   - Creates and closes many temporary Photoshop documents.
 *   - Writes PNG files to the selected folder.
 */

var outFolder = Folder.selectDialog("Select output folder for Inner Shadow dataset");
if (!outFolder) {
    alert("No output folder selected. Exiting.");
    throw new Error("No output folder");
}

var angles       = [0, 90, 180, 270];
var distances    = [5, 15, 30];
var sizes        = [10, 30];
var chokes       = [0, 20];
var fxOpacities  = [75, 100];
var fxBlendModes = [
    { key: "Nrml", name: "normal" },
    { key: "Mltp", name: "multiply" }
];

function pxValue(v) {
    if (v === undefined || v === null) return 0;
    if (typeof v === "number") return v;
    if (typeof v.as === "function") return v.as("px");
    if (typeof v.value !== "undefined") return v.value;
    return Number(v);
}

function createDocument(name, width, height) {
    try {
        return app.documents.add(width, height, 72, name, NewDocumentMode.RGB, DocumentFill.TRANSPARENT);
    } catch (e) {
        return app.documents.add(width, height, 72, name, NewDocumentMode.RGB);
    }
}

function addBlackRectangle(doc) {
    var w = pxValue(doc.width);
    var h = pxValue(doc.height);
    var margin = Math.round(Math.min(w, h) * 0.25);

    var layer = doc.artLayers.add();
    layer.name = "shape";

    var region = [
        [margin, margin],
        [w - margin, margin],
        [w - margin, h - margin],
        [margin, h - margin]
    ];

    doc.selection.select(region);

    var black = new SolidColor();
    black.rgb.red = 0;
    black.rgb.green = 0;
    black.rgb.blue = 0;

    doc.selection.fill(black);
    doc.selection.deselect();

    return layer;
}

function blendModeTypeID(mode) {
    try { return charIDToTypeID(mode); }
    catch (e) { return stringIDToTypeID(mode); }
}

function applyInnerShadow(params) {
    var desc = new ActionDescriptor();

    var ref = new ActionReference();
    ref.putProperty(charIDToTypeID("Prpr"), charIDToTypeID("Lefx"));
    ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
    desc.putReference(charIDToTypeID("null"), ref);

    var fxDesc = new ActionDescriptor();

    var isDesc = new ActionDescriptor();
    isDesc.putBoolean(charIDToTypeID("enab"), true);
    isDesc.putBoolean(charIDToTypeID("present"), true);
    isDesc.putBoolean(charIDToTypeID("showInDialog"), true);

    isDesc.putEnumerated(charIDToTypeID("Blnd"), charIDToTypeID("BlnM"), blendModeTypeID(params.blendMode));

    var clr = new ActionDescriptor();
    clr.putDouble(charIDToTypeID("Rd  "), 0);
    clr.putDouble(charIDToTypeID("Grn "), 0);
    clr.putDouble(charIDToTypeID("Bl  "), 0);
    isDesc.putObject(charIDToTypeID("Clr "), charIDToTypeID("RGBC"), clr);

    isDesc.putInteger(charIDToTypeID("Opct"), params.opacity);
    isDesc.putInteger(charIDToTypeID("lagl"), params.angle);
    isDesc.putBoolean(charIDToTypeID("uglg"), false);
    isDesc.putInteger(charIDToTypeID("Dstn"), params.distance);
    isDesc.putInteger(charIDToTypeID("Ckmt"), params.choke);
    isDesc.putInteger(charIDToTypeID("blur"), params.size);
    isDesc.putInteger(charIDToTypeID("Nose"), 0);

    fxDesc.putObject(charIDToTypeID("IrSh"), charIDToTypeID("IrSh"), isDesc);
    desc.putObject(charIDToTypeID("T   "), charIDToTypeID("Lefx"), fxDesc);

    executeAction(charIDToTypeID("setd"), desc, DialogModes.NO);
}

function saveTransparentPng(doc, file) {
    var pngOptions = new PNGSaveOptions();
    pngOptions.compression = 6;
    pngOptions.interlaced = false;
    doc.saveAs(file, pngOptions, true, Extension.LOWERCASE);
}

var count = 0;
var errors = 0;
var total = angles.length * distances.length * sizes.length * chokes.length * fxOpacities.length * fxBlendModes.length;

for (var a = 0; a < angles.length; a++) {
    for (var d = 0; d < distances.length; d++) {
        for (var s = 0; s < sizes.length; s++) {
            for (var c = 0; c < chokes.length; c++) {
                for (var o = 0; o < fxOpacities.length; o++) {
                    for (var b = 0; b < fxBlendModes.length; b++) {
                        var params = {
                            angle:     angles[a],
                            distance:  distances[d],
                            size:      sizes[s],
                            choke:     chokes[c],
                            opacity:   fxOpacities[o],
                            blendMode: fxBlendModes[b].key
                        };

                        var fileName = "is_" +
                            "a" + params.angle + "_" +
                            "d" + params.distance + "_" +
                            "s" + params.size + "_" +
                            "c" + params.choke + "_" +
                            "op" + params.opacity + "_" +
                            "bm" + fxBlendModes[b].name +
                            ".png";

                        var file = new File(outFolder + "/" + fileName);
                        if (file.exists) { count++; continue; }

                        var doc = createDocument("inner_shadow_test", 256, 256);
                        var layer = addBlackRectangle(doc);

                        try {
                            applyInnerShadow(params);
                            saveTransparentPng(doc, file);
                        } catch (e) {
                            $.writeln("Error: " + fileName + " — " + e);
                            errors++;
                        } finally {
                            doc.close(SaveOptions.DONOTSAVECHANGES);
                        }

                        count++;
                        if (count % 10 === 0) {
                            $.writeln("Progress: " + count + " / " + total + " (errors: " + errors + ")");
                        }
                    }
                }
            }
        }
    }
}

alert("Done. Generated " + count + " images, " + errors + " errors.\n" + outFolder.fsName);
